打字稿通用类型断言
Typescript Generic Type Assertion
下面是我对打字稿的观察总结。
这是一些代码:
type someTypeEnum = '1';
type someOtherTypeEnum = '2' | '3';
type combinedTypeEnum = someTypeEnum | someOtherTypeEnum;
这是第一种情况:-
function typeAssertion<T extends combinedTypeEnum>(args: T): args is someTypeEnum {
// The error i get
// A type predicate's type must be assignable to its parameter's type.
// Type '"1"' is not assignable to type 'T'.
return undefined;
}
我不明白为什么这件事会失败,因为我们已经将参数限制为 combinedTypeEnum,以防万一
typeAssertion('4')
我们已经收到一个错误,指出 '4'
不是有效参数,那么为什么 args is someTypeEnum
被认为是无效谓词。
这是第二种情况:-
function typeAssertion(args: combinedTypeEnum): args is someTypeEnum {
return undefined;
}
这似乎工作正常,但万一我们这样做:-
function someFunction<T extends combinedTypeEnum>(args: T): T {
if (typeAssertion(args)) {
// args here is 'T & "1"'
args
}
return args
};
为什么我们有 T & "1" 而不是只有 "1",我们特别断言它是 someTypeEnum。
我真的很好奇为什么会做出这样的决定。
如果事情以不同的方式完成,那么看看事情会如何破裂真的很有帮助。
当您有字符串文字时,extends
没有多大意义。为了使解释更容易,让我使用其他类型。考虑这三个 类:
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
当我们使用泛型时,实际类型由调用者设置:
function foo<T extends Animal>(arg: T) {}
foo(new Dog()); //T is Dog, equivalent to foo(arg: Dog) {}
foo(new Cat()); //T is Cat, equivalent to foo(arg: Cat) {}
现在您可能已经知道我们要去哪里了。让我们使用类型谓词:
function foo<T extends Animal>(arg: T): arg is Cat {}
当我们调用 foo(new Dog())
时,最后一个示例等同于此:
function foo(arg: Dog): arg is Cat {}
当然它不起作用或没有意义。
至于你的第二个例子:变量的类型没有改变。关键是通过断言一个特定的类型,编译器允许你做任何可以用这个类型做的事情。
更新:
或更简单:
function typeAssertion(args: combinedTypeEnum): args is someTypeEnum {
return args === "1";
}
原文:
这也让我难住了好久。实际上解决方案(至少在2021年,不确定问问题时是否已经返回)是:
function typeAssertion<T extends combinedTypeEnum>(args: T): args is T & someTypeEnum {
return args === "1";
}
这背后的想法(据我从 了解)是这样的:当您调用 typeAssertion("2")
时,T
获得值 "2"
(文字类型 "2"
),这意味着您最终得到的函数是:
function typeAssertion(args: "2"): args is someTypeEnum
这显然没有意义。我不确定解决方法(T &
)是否更有意义,但它有效:
type someTypeEnum = '1';
type someOtherTypeEnum = '2' | '3';
type combinedTypeEnum = someTypeEnum | someOtherTypeEnum;
function typeAssertion<T extends combinedTypeEnum>(args: T): args is T & someTypeEnum {
return args === "1";
}
const a: combinedTypeEnum = "1"
const b: combinedTypeEnum = "2"
const c: combinedTypeEnum = "3"
const d = "1"
const e = "2"
const f = "4"
let one: "1" = "1"
if (typeAssertion(a)) one = a
if (typeAssertion(b)) one = b
if (typeAssertion(c)) one = c
if (typeAssertion(d)) one = d
if (typeAssertion(e)) one = e
if (typeAssertion(f)) one = f // this one gives an error
下面是我对打字稿的观察总结。
这是一些代码:
type someTypeEnum = '1';
type someOtherTypeEnum = '2' | '3';
type combinedTypeEnum = someTypeEnum | someOtherTypeEnum;
这是第一种情况:-
function typeAssertion<T extends combinedTypeEnum>(args: T): args is someTypeEnum {
// The error i get
// A type predicate's type must be assignable to its parameter's type.
// Type '"1"' is not assignable to type 'T'.
return undefined;
}
我不明白为什么这件事会失败,因为我们已经将参数限制为 combinedTypeEnum,以防万一
typeAssertion('4')
我们已经收到一个错误,指出 '4'
不是有效参数,那么为什么 args is someTypeEnum
被认为是无效谓词。
这是第二种情况:-
function typeAssertion(args: combinedTypeEnum): args is someTypeEnum {
return undefined;
}
这似乎工作正常,但万一我们这样做:-
function someFunction<T extends combinedTypeEnum>(args: T): T {
if (typeAssertion(args)) {
// args here is 'T & "1"'
args
}
return args
};
为什么我们有 T & "1" 而不是只有 "1",我们特别断言它是 someTypeEnum。
我真的很好奇为什么会做出这样的决定。 如果事情以不同的方式完成,那么看看事情会如何破裂真的很有帮助。
extends
没有多大意义。为了使解释更容易,让我使用其他类型。考虑这三个 类:
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
当我们使用泛型时,实际类型由调用者设置:
function foo<T extends Animal>(arg: T) {}
foo(new Dog()); //T is Dog, equivalent to foo(arg: Dog) {}
foo(new Cat()); //T is Cat, equivalent to foo(arg: Cat) {}
现在您可能已经知道我们要去哪里了。让我们使用类型谓词:
function foo<T extends Animal>(arg: T): arg is Cat {}
当我们调用 foo(new Dog())
时,最后一个示例等同于此:
function foo(arg: Dog): arg is Cat {}
当然它不起作用或没有意义。
至于你的第二个例子:变量的类型没有改变。关键是通过断言一个特定的类型,编译器允许你做任何可以用这个类型做的事情。
更新:
或更简单:
function typeAssertion(args: combinedTypeEnum): args is someTypeEnum {
return args === "1";
}
原文:
这也让我难住了好久。实际上解决方案(至少在2021年,不确定问问题时是否已经返回)是:
function typeAssertion<T extends combinedTypeEnum>(args: T): args is T & someTypeEnum {
return args === "1";
}
这背后的想法(据我从 typeAssertion("2")
时,T
获得值 "2"
(文字类型 "2"
),这意味着您最终得到的函数是:
function typeAssertion(args: "2"): args is someTypeEnum
这显然没有意义。我不确定解决方法(T &
)是否更有意义,但它有效:
type someTypeEnum = '1';
type someOtherTypeEnum = '2' | '3';
type combinedTypeEnum = someTypeEnum | someOtherTypeEnum;
function typeAssertion<T extends combinedTypeEnum>(args: T): args is T & someTypeEnum {
return args === "1";
}
const a: combinedTypeEnum = "1"
const b: combinedTypeEnum = "2"
const c: combinedTypeEnum = "3"
const d = "1"
const e = "2"
const f = "4"
let one: "1" = "1"
if (typeAssertion(a)) one = a
if (typeAssertion(b)) one = b
if (typeAssertion(c)) one = c
if (typeAssertion(d)) one = d
if (typeAssertion(e)) one = e
if (typeAssertion(f)) one = f // this one gives an error