首页 > 解决方案 > 如何在打字稿中打开泛型对象的属性?

问题描述

我有一个属性类型是通用的类型。

我想打开属性来推断泛型值的类型。

这是我为实现这一目标所做的代码。我认为这会起作用,因为编译器应该具有推断类型所需的所有信息。显然不是,因为编译器会抛出错误。

type Foo<T> = {
    value: T
}

type A = { type: 'a', data: number }
type B = { type: 'b', data: string }
type AB = A | B

function doStuff(foo: Foo<AB>) {
    switch(foo.value.type) {
        case 'a': {
            // here TS knows that foo.value is an `A`, why isnt foo a Foo<A> ?
            return doStuffA(foo) // Error (1) on foo
        }
        case 'b': {
            return doStuffB(foo) // Error(2) also on foo
        }
    }
}

function doStuffA(foo: Foo<A>) {
    // ...
}

function doStuffB(foo: Foo<B>) {
    // ...
}

和错误:

(Error 1)
Argument of type 'Foo<AB>' is not assignable to parameter of type 'Foo<A>'.
  Type 'AB' is not assignable to type 'A'.
    Type 'B' is not assignable to type 'A'.
      Types of property 'type' are incompatible.
        Type '"b"' is not assignable to type '"a"'.

(Error 2)
Argument of type 'Foo<AB>' is not assignable to parameter of type 'Foo<B>'.
  Type 'AB' is not assignable to type 'B'.
    Type 'A' is not assignable to type 'B'.
      Types of property 'type' are incompatible.
        Type '"a"' is not assignable to type '"b"'.

这是 Typescript 的限制吗?或者我做错了什么?

标签: typescripttypescript-generics

解决方案


感谢评论中的 Ben Wainwright,我找到了解决方案。

我需要创建改进类型的函数Foo<T>

type Foo<T> = {
    value: T
}

type A = { type: 'a', data: number }
type B = { type: 'b', data: string }
type AB = A | B

// here, isA tells the TS compiler that foo is indeed a Foo<A>
function isA(foo: Foo<AB>): foo is Foo<A> {
    return foo.value.type === 'a'
}

// same here for Foo<B>
function isB(foo: Foo<AB>): foo is Foo<B> {
    return foo.value.type === 'b'
}

function doStuff(foo: Foo<AB>) {
    if(isA(foo)) {
        // it works ! here TS recognise foo as Foo<A>
        return doStuffA(foo)
    } else if(isB(foo)) {
        // same here, TS knows that foo is a Foo<B>
        return doStuffB(foo)
    }
}

function doStuffA(foo: Foo<A>) {
    // ...
}

function doStuffB(foo: Foo<B>) {
    // ...
}

推荐阅读