简体   繁体   English

打字稿通用类型断言

[英]Typescript Generic Type Assertion

So Here is a summary of my observation working with typescript.所以这是我对打字稿的观察总结。

Here is some code:这是一些代码:

type someTypeEnum = '1';
type someOtherTypeEnum = '2' | '3';
type combinedTypeEnum = someTypeEnum | someOtherTypeEnum;

Here is the first case :-这是第一种情况:-

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;
}

I cannot understand why this thing fails coz we have already limited our arguments to combinedTypeEnum, in case we do我不明白为什么这件事会失败,因为我们已经将我们的参数限制为组合类型枚举,以防万一

typeAssertion('4')

We already get an error stating '4' is not a valid argument so why is it that args is someTypeEnum is considered an in-valid predicate.我们已经收到一个错误,指出'4'不是一个有效的参数,那么为什么args is someTypeEnum被认为是一个无效的谓词。

Here is the second case :-这是第二种情况:-

function typeAssertion(args: combinedTypeEnum): args is someTypeEnum {
    return undefined;
}

This seems to work fine but in case we do this :-这似乎工作正常,但如果我们这样做:-

function someFunction<T extends combinedTypeEnum>(args: T): T {
    if (typeAssertion(args)) {
        // args here is  'T & "1"' 
        args
    }
    return args
};

why is it that we have T & "1" and not only "1", we specifically asserted that it is someTypeEnum.为什么我们有 T & "1" 而不仅仅是 "1",我们特别断言它是 someTypeEnum。

I was really curious as to why such decisions were made.我真的很好奇为什么会做出这样的决定。 It would be really helpful to see how things break in case things were done in a different manner.如果事情以不同的方式完成,那么看看事情如何破裂会非常有帮助。

extends doesn't make much sense when you have string literals.当您有字符串文字时, extends没有多大意义。 To make the explanation easier let me use other types.为了使解释更容易,让我使用其他类型。 Consider these three classes:考虑这三个类:

class Animal {}

class Dog extends Animal {}

class Cat extends Animal {}

when we use generics the actual type is set by the caller:当我们使用泛型时,实际类型由调用者设置:

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) {}

Now you may already see where we are going.现在你可能已经看到我们要去哪里了。 Let's use a type predicate:让我们使用类型谓词:

function foo<T extends Animal>(arg: T): arg is Cat {}

When we call foo(new Dog()) the last example becomes equivalent to this:当我们调用foo(new Dog()) ,最后一个例子就变成了这样:

function foo(arg: Dog): arg is Cat {}

And of course it doesn't work or make sense.当然,它不起作用或没有意义。

As for your second example: The type of the variable doesn't change.至于你的第二个例子:变量的类型不会改变。 The point is that by asserting a specific type the compiler allows you to do whatever can be done with this type.关键是通过断言一个特定的类型,编译器允许你对这个类型做任何可以做的事情。

UPDATE:更新:

Or much simpler:或者更简单:

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

See this playground看到这个游乐场


Original:原来的:

This had me stumped for a long while as well.这也让我难倒了很长时间。 Actually the solution (at least in 2021, not sure if it was back when the question was asked) is:实际上,解决方案(至少在 2021 年,不确定在提出问题时是否已恢复)是:

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

The idea behind this (as far as I understand it from this answer ) is this: when you call typeAssertion("2") , the T gets the value "2" (literal type "2" ), meaning that you end up with the function:这背后的想法(据我从这个答案中理解)是这样的:当你调用typeAssertion("2")T得到值"2" (文字类型"2" ),这意味着你最终得到功能:

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

which obviously doesn't make sense.这显然没有意义。 I'm not sure the workaround (with T & ) makes more sense, but it works:我不确定解决方法(使用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

See in Playground 在操场上看

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM