Typescript:有没有一种方法可以根据属性的值来更改类型?

时间:2019-05-06 19:59:14

标签: typescript visual-studio-code typescript-typings

我正在尝试根据“键”属性的值更改对象的类型。

我有一些类型,例如AElementBElement,...,ZElement。每个元素都有一个称为“名称”的通用属性。因此,取决于该属性,必须更改类型。

例如:

// Elements
type AElement = {name:"a"; propA: string;}
type BElement = {name:"b"; propB: number;}
type CElement = {name:"c"; propC: string;}
// ...
type ZElement = {name:"z"; propZ: string; propZZ: number;}

// Map interface
interface ElementsMap {
    "a": AElement;
    "b": BElement;
    "c": CElement;
    //...
    "z": ZElement
}

// My custom type
type Elem<K extends keyof ElementsMap = keyof ElementsMap> = ElementsMap[K];

// Use it
let elements:Elem[] = [{
    name: "a",
    propA: "123",
},{
    name: "c",
    propC: "321",
},{
    name: "z",
    propZ: "123",
    propZZ: 123,
}];

// Test
let test1 = elements[2];
let test2: Elem = {
    name: "a",
    propA: "123",
}

我希望当我使用Element[]时,每种类型都取决于键属性“名称”,我可以使用该类型的不同道具。但是test1和test2的变量类型是:每个变量AElement | BElement | CElement | ZElement,但是我希望ZElementAElement

1 个答案:

答案 0 :(得分:0)

不幸的是,这是“数组”的基础“功能”,并且按预期工作,即使在特定索引下对数组进行索引也将始终产生该数组类型,即使该类型是联合。

无论索引处的值是什么,它都会始终产生Arrays类型,

只能在一个键处索引元组以接收该键处的类型,这是因为它们在运行时具有已知的长度,而Array则没有。

以下面的代码为例。

const testTuple: [AElement, CElement, ZElement] = [{
    name: "a",
    propA: "123",
},{
    name: "c",
    propC: "321",
},{
    name: "z",
    propZ: "123",
    propZZ: 123,
}];
const TestTypeAtIndex = testTuple[0] // AElement and not a union.

有很多解决方法,如果您想了解更多,请发表评论,但是我想说,最简单的就是添加一个用户定义的typeguard,更复杂的解决方法可以提供更好的生活质量,复杂的实现。

// use it as array.
const testTuple: Elem[] = [{
    name: "a",
    propA: "123",
},{
    name: "c",
    propC: "321",
},{
    name: "z",
    propZ: "123",
    propZZ: 123,
}];

const isAElement = (ele: ElementsMap[keyof ElementsMap]): ele is AElement => {
    return "propA" in ele;
}

const testTypeAtIndex = testTuple[0] // union of everything
if(isAElement(testTypeAtIndex)) {
    const newTestType = testTypeAtIndex; // inside here its JUST AElement because of typeguard.
}