打字稿:在条件语句中使用条件类型
Typescript: using conditional typing in conditional statements
假设我有一些联合类型:
var MyComplexType = MyType1 | MyType2 | MyType3 | ... | MyTypeN
其中 MyType{N}
有这种签名:
type MyType1 = {
type: string,
data: <different data for different types>
}
我知道我可以使用一种类型保护函数,e。 g.:
function isMyComplexTypeOfMyType1(item: MyComplexType): item is MyType1 {
return item.type == "type of MyType1"
}
但在这种情况下我应该写很多这样的函数。
所以,问题是:我可以在条件语句(if ... else
或 switch ... case
)中动态定义类型吗?例如:
function someFunction(item: MyComplexType) {
switch (item.type) {
case "type of MyType1":
// item is MyType1
// do something
break
case "type of MyType2":
// item is MyType2
// do something
break
...
}
}
如果您打算使用 switch/case
语句检查 union-typed 值,您应该将其设为 disciminated union where the type
property of each constituent of the union is declared to be the relevant string literal 而不仅仅是 string
。你真的不需要条件类型来处理这个问题,至少在你的 someFunction()
实现中不需要。
例如,假设您的类型如下所示:
type MyType1 = { type: "type1", data: { a: string, b: number } };
type MyType2 = { type: "type2", data: { c: boolean, d: string } };
type MyType3 = { type: "type3", data: { e: number, f: boolean } };
type MyComplexType = MyType1 | MyType2 | MyType3;
然后编译器会自动将对 MyComplexType["type"]
的检查视为类型保护,如下所示:
const exhaustivenessCheck = (x: never) => x;
function someFunction(item: MyComplexType) {
switch (item.type) {
case "type1":
console.log(2 * item.data.b); // okay
break;
case "type2":
console.log(item.data.d.charAt(0)); // okay
break;
case "type3":
console.log(7 - item.data.e); // okay
break;
default:
throw exhaustivenessCheck(item); // okay
}
}
如果函数以某种方式落入 default
,那么 exhaustivenessCheck()
基本上是一个 throw
语句。这不应该发生,但有用的是,如果编译器认为您没有检查所有内容,它会警告您。那是因为 exhaustivenessCheck()
要求它的参数是 never
类型,这是不可能发生的。如果您注释掉 case "type3"
子句,或者稍后向 MyComplexType
联合添加一个新成分,exhaustivenessCheck()
行将抛出一个错误,指出您未能检查一个案例。
此时你可以停下来,但如果你的类型真的是程序化的,因为它们只包含两个属性,一个 type
判别字符串和一个 data
属性,那么您可以像这样以更少的重复定义您的类型:
// a mapping from type string to data type
type MyTypes = {
type1: { a: string, b: number };
type2: { c: boolean, d: string };
type3: { e: number, f: boolean };
}
// convert the mapping to the union of types
type MyType<K extends keyof MyTypes = keyof MyTypes> = {
[P in K]: { type: P, data: MyTypes[P] }
}[K]
您可以验证 MyType
或 MyType<keyof MyTypes>
扩展到我上面定义的 MyComplexType
并集。您原来的 MyType1
现在是 MyType<"type1">
,依此类推。也就是说,如果您需要为类型使用旧名称,您可以这样做:
type MyType1 = MyType<"type1">;
type MyType2 = MyType<"type2">;
type MyType3 = MyType<"type3">
type MyComplexType = MyType;
希望对您有所帮助;祝你好运!
假设我有一些联合类型:
var MyComplexType = MyType1 | MyType2 | MyType3 | ... | MyTypeN
其中 MyType{N}
有这种签名:
type MyType1 = {
type: string,
data: <different data for different types>
}
我知道我可以使用一种类型保护函数,e。 g.:
function isMyComplexTypeOfMyType1(item: MyComplexType): item is MyType1 {
return item.type == "type of MyType1"
}
但在这种情况下我应该写很多这样的函数。
所以,问题是:我可以在条件语句(if ... else
或 switch ... case
)中动态定义类型吗?例如:
function someFunction(item: MyComplexType) {
switch (item.type) {
case "type of MyType1":
// item is MyType1
// do something
break
case "type of MyType2":
// item is MyType2
// do something
break
...
}
}
如果您打算使用 switch/case
语句检查 union-typed 值,您应该将其设为 disciminated union where the type
property of each constituent of the union is declared to be the relevant string literal 而不仅仅是 string
。你真的不需要条件类型来处理这个问题,至少在你的 someFunction()
实现中不需要。
例如,假设您的类型如下所示:
type MyType1 = { type: "type1", data: { a: string, b: number } };
type MyType2 = { type: "type2", data: { c: boolean, d: string } };
type MyType3 = { type: "type3", data: { e: number, f: boolean } };
type MyComplexType = MyType1 | MyType2 | MyType3;
然后编译器会自动将对 MyComplexType["type"]
的检查视为类型保护,如下所示:
const exhaustivenessCheck = (x: never) => x;
function someFunction(item: MyComplexType) {
switch (item.type) {
case "type1":
console.log(2 * item.data.b); // okay
break;
case "type2":
console.log(item.data.d.charAt(0)); // okay
break;
case "type3":
console.log(7 - item.data.e); // okay
break;
default:
throw exhaustivenessCheck(item); // okay
}
}
如果函数以某种方式落入 default
,那么 exhaustivenessCheck()
基本上是一个 throw
语句。这不应该发生,但有用的是,如果编译器认为您没有检查所有内容,它会警告您。那是因为 exhaustivenessCheck()
要求它的参数是 never
类型,这是不可能发生的。如果您注释掉 case "type3"
子句,或者稍后向 MyComplexType
联合添加一个新成分,exhaustivenessCheck()
行将抛出一个错误,指出您未能检查一个案例。
此时你可以停下来,但如果你的类型真的是程序化的,因为它们只包含两个属性,一个 type
判别字符串和一个 data
属性,那么您可以像这样以更少的重复定义您的类型:
// a mapping from type string to data type
type MyTypes = {
type1: { a: string, b: number };
type2: { c: boolean, d: string };
type3: { e: number, f: boolean };
}
// convert the mapping to the union of types
type MyType<K extends keyof MyTypes = keyof MyTypes> = {
[P in K]: { type: P, data: MyTypes[P] }
}[K]
您可以验证 MyType
或 MyType<keyof MyTypes>
扩展到我上面定义的 MyComplexType
并集。您原来的 MyType1
现在是 MyType<"type1">
,依此类推。也就是说,如果您需要为类型使用旧名称,您可以这样做:
type MyType1 = MyType<"type1">;
type MyType2 = MyType<"type2">;
type MyType3 = MyType<"type3">
type MyComplexType = MyType;
希望对您有所帮助;祝你好运!