1

我有一个更复杂问题的简化版本。以下导致 TSC 抛出错误:

type Demo<isTrue> = isTrue extends true ? { a: string } : isTrue extends false ? { b: string } : never;

const func = <T extends boolean>(arg: T): Demo<T> => {
    if (arg) {
        return {a: "hello" };
    } else {
        return { b: "world" };
    }
};

const out = func(true);

引发以下错误:

    Type '{ a: string; }' is not assignable to type 'Demo<T>'.
    Type '{ b: string; }' is not assignable to type 'Demo<T>'.

out底部的检查类型正确,所以只是函数定义有问题。我怎样才能更好地理解这一点以及如何解决它?

游乐场链接

4

2 回答 2

2

我添加了重载并Demo<boolean>作为返回类型。

在这种特殊情况下T extends boolean,实际上与Demo<boolean>.

但请记住,泛型很棘手。extends不代表equal

type Demo<isTrue> = isTrue extends true ? { a: string } : isTrue extends false ? { b: string } : never;


function func(arg: false): Demo<false>
function func(arg: true): Demo<true>
function func(arg: boolean): Demo<boolean> {
    if (arg === true) {
        const a = arg;
        return { a: "hello" };
    } else {
        return { b: "world" };
    }
};

const out = func(true);

游乐场链接

于 2021-02-22T07:14:05.223 回答
2

我怎样才能更好地理解这一点?

看看这个 GitHub 线程(另见原始问题)。归结为 TypeScript 在使用条件类型时不支持缩小函数返回类型的事实。由于Demo类型的解析依赖于泛型类型参数T,所以就如同直接在返回类型注解中编写条件一样。

如果我们重写Demo类型,问题应该会变得更清楚(仅用于演示目的):

type D<T extends boolean> = {
    true: {
        a: string
    },
    false: {
        b: string
    }
}[`${T}`];

const func = <T extends boolean>(arg: T): D<T> => {
    if (arg) {
        return {a: "hello" }; //Type '{ a: string; }' is not assignable to type '{ a: string; } & { b: string; }'
    } else {
        return { b: "world" }; //Type '{ b: string; }' is not assignable to type '{ a: string; } & { b: string; }'
    }
};

现在应该很清楚,在您为类型参数提供参数之前D<T>,该问题仍未解决。这就是正确推断的原因。const out = func(true);

我该如何解决?

您几乎只能使用类型断言as Demo<T>或删除泛型类型参数,并使用船长-yossarian 的回答中概述的重载重写签名。

于 2021-02-22T08:03:02.667 回答