要让Res2Type
知道res1
的元素的name
个属性中的literal types个属性,唯一的方法是让它成为res1
的类型中的generic或其他相关类型. 这里有一种写法:
type Res2Type<T extends Res1Type> = {
AlwaysPresent1: string;
AlwaysPresent2: number;
} & Record<T[number]["name"], SubType>
所以我们希望res2
是Res2Type<typeof res1>
类型,使用TS typeof
operator:
但我们需要小心.如果你只是annotate,res1
,作为类型Res1Type
,就像
const res1: Res1Type = [ ⋯ ];
然后,该变量的类型将是widened到Res1Type
,并忽略有关初始化器表达式的任何特定内容.这将意味着res2
的Res2Type<Res1Type>
类型看起来像{ AP1: string; AP2: string} & {[k: string]: SubType }
,intersection type很难使用(有关这种类型的讨论,请参见How to define Typescript type as a dictionary of strings but with one numeric "id" property),并且实际上根本不约束res2
的键.
我们应该使用the satisfies
operator而不是注释来对照Res1Type
判断推断的初始化器类型,而不是扩大它:
const res1 = [ ⋯ ] satisfies Res1Type;
但我们still需要小心,因为推断出的name
个属性的类型仍然是string
.像{name: "xxx"}
这样的对象被推断为类型{name: string}
而不是{name: "xxx"}
.如果我们想要后者,我们需要给编译器一个提示,我们关心文字类型.最简单的方法是在表达式上使用const
assertion:
const res1 = [ ⋯ ] as const satisfies Res1Type;
而that美元足以让它发挥作用.
那么,让我们看看我们得到了什么:
const res1 = [
{
name: "FieldNameA",
value: 123
},
{
name: "FieldNameB",
value: 123
}
] as const satisfies Res1Type;
/* const res1: [{
readonly name: "FieldNameA";
readonly value: 123;
}, {
readonly name: "FieldNameB";
readonly value: 123;
}] */
它编译时没有错误(在TS5.3+中),您可以看到它跟踪"FieldNameA"
和"FieldNameB"
.所以我们想要res2
的类型是
type R2Test = Res2Type<typeof res1>;
/* type R2Test = {
AlwaysPresent1: string;
AlwaysPresent2: number;
} & Record<"FieldNameA" | "FieldNameB", SubType> */
如果需要,可以使用该类型对res2
进行注释:
const res2: Res2Type<typeof res1> = {
AlwaysPresent1: "test",
AlwaysPresent2: 1,
FieldNameA: {
field1: 1,
field2: 2
},
FieldNameB: {
field1: 1,
field2: 2
}
}; // okay
或者,您也可以根据以后的需要继续使用as const satisfies
:
const res2 = {
AlwaysPresent1: "test",
AlwaysPresent2: 1,
FieldNameA: {
field1: 1,
field2: 2
},
FieldNameB: {
field1: 1,
field2: 2
}
} as const satisfies Res2Type<typeof res1>; // okay
Playground link to code
Res2Type
type Res1Type = {
name: string;
value: number;
}[];
const res1 = [
{
name: "FieldNameA",
value: 123
},
{
name: "FieldNameB",
value: 123
}
] as const satisfies Res1Type;
type SubType = {
field1: number;
field2: number;
};