打字稿:在条件语句中使用条件类型 [英] Typescript: using conditional typing in conditional statements
问题描述
假设我有一些联合类型:
Assume I have some a-lot-of-union type:
var MyComplexType = MyType1 | MyType2 | MyType3 | ... | MyTypeN
其中 MyType{N}
具有这种签名:
where MyType{N}
has this kind of signature:
type MyType1 = {
type: string,
data: <different data for different types>
}
我知道我可以使用一种类型保护函数,例如.:
I know that I can use a kind of type guard function, e. g.:
function isMyComplexTypeOfMyType1(item: MyComplexType): item is MyType1 {
return item.type == "type of MyType1"
}
但在这种情况下,我应该编写很多此类函数.
but in this case I should write a lot of this kind of functions.
那么,问题是:我可以在条件语句(if ... else
或 switch ... case
)中动态定义类型吗?例如:
So, the question is: can I dynamically define type inside a conditional statements (if ... else
or switch ... case
)? For example:
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
语句检查联合类型的值,您可能应该将其设为 歧视联合 其中 type
属性联盟的每个组成部分都被声明为相关的 字符串文字 而不仅仅是string
.你真的不需要条件类型来处理这个问题,至少在你的 someFunction()
实现中不需要.
If you plan to check a union-typed value with a switch/case
statement, you should probably make it a disciminated union where the type
property of each constituent of the union is declared to be the relevant string literal instead of just string
. You don't really need conditional types to deal with this, at least not inside your someFunction()
implementation.
例如,假设您的类型如下所示:
For example, let's say your types look like this:
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"]
上的检查视为类型保护,如下所示:
Then the compiler will automatically treat checks on MyComplexType["type"]
as a type guard, like this:
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
}
}
exhaustivenessCheck()
基本上是一个 throw
语句,如果函数以某种方式失败到 default
.这不应该发生,但有用的是,如果编译器认为您没有检查所有内容,它会警告您.那是因为 exhaustivenessCheck()
要求其参数的类型为 never
,这是不可能发生的.如果您注释掉 case "type3"
子句,或者稍后向 MyComplexType
联合添加一个新成分,exhaustivenessCheck()
行将抛出错误,说明您未能检查案例.
That exhaustivenessCheck()
is basically a throw
statement if the function somehow falls through to default
. That shouldn't happen, but the usefulness is that the compiler will warn you if it doesn't think you checked everything. That's because exhaustivenessCheck()
requires its parameter to be of type never
, which can't happen. If you comment out the case "type3"
clause, or sometime later add a new constituent to the MyComplexType
union, the exhaustivenessCheck()
line will throw an error saying you failed to check a case.
此时您可以停止,但如果您的类型真的是程序化的,因为它们只包含两个属性,一个 type
判别字符串和一个 data
属性,那么您可以像这样以更少的重复定义您的类型:
At this point you could stop, but if your types are really that programmatic in that they contain just two properties, a type
discriminant string and a data
property, then you can define your types with less repetition like this:
// 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
是否扩展为我上面定义的 MyComplexType
联合.您的旧 MyType1
现在是 MyType<"type1">
,依此类推.也就是说,如果您需要为类型使用旧名称,您可以这样做:
You can verify that MyType
or MyType<keyof MyTypes>
expands to the MyComplexType
union I defined above. Your old MyType1
is now MyType<"type1">
, and so forth. That is, if you need to use your old names for the types you can do it like this:
type MyType1 = MyType<"type1">;
type MyType2 = MyType<"type2">;
type MyType3 = MyType<"type3">
type MyComplexType = MyType;
希望有所帮助;祝你好运!
Hope that helps; good luck!
这篇关于打字稿:在条件语句中使用条件类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!