【问题标题】:TypeScript: Conditional generic types as function return values not assignableTypeScript:条件泛型类型作为函数返回值不可分配
【发布时间】:2019-10-13 20:28:35
【问题描述】:

我的一个通用函数中的可分配值有问题:

interface BuildArguments<T extends string> {
    type: T;
}

type PromiseResult<T> =
    T extends 'standalone' ? Promise<void> :
    T extends 'all' ? Promise<void> :
    Promise<void[]>;    

const foo: PromiseResult<'standalone'> = Promise.resolve();
const bar: PromiseResult<'all'> = Promise.resolve();
const baz: PromiseResult<'foo'> = Promise.resolve([]);

bundle({ type: 'foo' });

function bundle<T extends string>(buildArguments: BuildArguments<T>): PromiseResult<T> {
    switch (buildArguments.type) {
        case 'standalone':
            return Promise.resolve(); // error here, not assignable to PromiseResult<T>
        case 'all':
            return Promise.resolve(); // error here, not assignable to PromiseResult<T>
        default:
            return Promise.all([ // error here, not assignable to PromiseResult<T>
                Promise.resolve(),
                Promise.resolve()
            ]);
    }
}

consts foobarbaz 表明条件类型工作正常。如果您使用 ts 操场并将鼠标悬停在其上,则函数调用 bundle({ type: 'foo' }) 也正确提供了类型 Promise&lt;void[]&gt;。为什么它不适用于返回值? 如果这是由于 TypeScript 无法通过向函数添加 kind: T 参数来推断 T 引起的,我也尝试过,但没有任何更改。断言 Promise.resolve()PromiseResult&lt;T&gt; 工作正常。

【问题讨论】:

    标签: typescript


    【解决方案1】:

    Typescript 通常不会让您对条件类型进行太多操作,只要它们仍然具有未解析的条件类型(TPromiseResult&lt;T&gt; 中也是如此)

    此外,在这种情况下,您假设缩小buildArguments.type 缩小T。它不是。 Narrowing 缩小一个值,而不是整个类型参数。这是不可能的,考虑这个例子:

    function foo<T extends string | number>(a: T, b: T) {
        if(typeof a === "string") {
            // should b be string? No
        }
    }
    
    foo<string | number>(1, "");
    

    仅仅因为我们缩小了T 类型的一个值,就与其他此类变量无关。

    最简单的解决方案是使用更宽松的单独实现签名,同时将公共签名保留为对调用者更好的条件类型:

    function bundle<T extends string>(buildArguments: BuildArguments<T>): PromiseResult<T>
    function bundle(buildArguments: BuildArguments<string>): PromiseResult<'standalone' | 'all'> | PromiseResult<string> {
        switch (buildArguments.type) {
            case 'standalone':
                return Promise.resolve(); 
            case 'all':
                return Promise.resolve(); 
            default:
                return Promise.all([ 
                    Promise.resolve(),
                    Promise.resolve()
                ]);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-07-08
      • 1970-01-01
      • 2018-09-19
      • 2020-06-09
      • 2021-10-06
      • 1970-01-01
      • 1970-01-01
      • 2020-11-10
      相关资源
      最近更新 更多