Typescript 通用类型断言

Posted

技术标签:

【中文标题】Typescript 通用类型断言【英文标题】:Typescript Generic Type Assertion 【发布时间】:2019-08-21 06:18:47 【问题描述】:

以下是我对打字稿的观察总结。

这里有一些代码:

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;

我不明白为什么这件事会失败,因为我们已经将我们的参数限制为 combineTypeEnum,以防万一

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。

我真的很好奇为什么会做出这样的决定。 如果事情以不同的方式完成,看看事情是如何破裂的,这将非常有帮助。

【问题讨论】:

为什么这个类型保护函数需要是通用的? 【参考方案1】:

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 

当然它不起作用或没有意义。

至于你的第二个例子:变量的类型没有改变。关键是,通过声明一个特定的类型,编译器允许你做任何可以用这个类型做的事情。

【讨论】:

嗯,我想为这么晚的回复道歉,但我很好奇我们可以在这种情况下以某种方式使用重载。谢谢。【参考方案2】:

更新:

或者更简单:

function typeAssertion(args: combinedTypeEnum): args is someTypeEnum 
    return args === "1";

见this playground


原文:

这也让我困惑了很长时间。实际上解决方案(至少在 2021 年,不确定是否会在提出问题时恢复)是:

function typeAssertion<T extends combinedTypeEnum>(args: T): args is T & someTypeEnum 
    return args === "1";

这背后的想法(据我了解this answer)是这样的:当你调用typeAssertion("2")时,T得到值"2"(文字类型"2"),这意味着你以函数结束:

function typeAssertion(args: "2"): args is someTypeEnum

这显然没有意义。我不确定解决方法(使用T &amp;)是否更有意义,但它有效:

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

见in Playground

【讨论】:

以上是关于Typescript 通用类型断言的主要内容,如果未能解决你的问题,请参考以下文章

TypeScript专题之类型断言

TypeScript专题之类型断言

TypeScript-基础-08-类型断言

JSX 中的 TypeScript 类型断言

typeScript-基础知识-4-8类型断言

HTTP:从 JSON 对象到 Typescript 的类型断言