【问题标题】:Discriminated Unions of Function Types?函数类型的可区分联合?
【发布时间】:2020-02-16 17:31:41
【问题描述】:

我似乎无法弄清楚如何区分函数类型的可区分联合的成员。请参阅以下示例:

type _NumFunc = (n: number) => string;
type _StrFunc = (s: string) => string;
interface NumFunc extends _NumFunc { __type: 'NumFunc'; }
interface StrFunc extends _StrFunc { __type: 'StrFunc'; }
type Func = NumFunc | StrFunc;

let myNumFunc = ((n: number) => `Hello x${n}!`) as NumFunc;
let myStrFunc = ((s: string) => `Hello, ${s}!`) as StrFunc;

let funcGen = (n: number): Func => n % 2 == 0 ? myNumFunc : myStrFunc;

for (let i = 0; i < 2; i++)
{
    let func = funcGen(i);
    switch (func.__type)
    {
    case 'NumFunc':
        console.log(func(3));
        break;
    case 'StrFunc':
        console.log(func('World!'));
        break;
    default:
        console.error(func);
        console.error('How did this happen?');
        break;
    }
}

我希望这个程序的输出应该是:

你好 x3!

你好,世界!

但是如果您run this code,您会看到每次迭代都会调用默认情况。简单地记录func 将显示函数对象,但尝试访问对象上的__type 会引发错误,指出func 的类型是never。为什么这种方法不起作用,是否有任何方法允许使用函数类型的可区分联合?

【问题讨论】:

    标签: typescript


    【解决方案1】:

    好问题。我们需要了解 TypeScript 没有运行时。这意味着,运行时中没有类型的表示。类型只是 JS 本身存在的真实结构的别名。换句话说,当你定义一个 TS 类型时,你需要告诉编译器这个类型在运行时所代表的确切结构。

    这意味着如果我说某个类型 A 表示为 {x: string},那么当我创建一个类型为 A 的值时,我需要在其中放置一些对象,并且将 x 属性作为字符串。 TypeScript 永远不会自己创建这样的结构。它需要从服务器响应中创建或给出。所以这是运行时的责任。

    回到您的问题 - 问题是您正在定义您的函数以 __type 属性的形式具有判别性,但您从未真正在其中任何一个中设置此属性。所以你在愚弄类型系统,说 f 是 NumFunc 而 g 是 StrFunc,但这在运行时没有真正的表示。 Switch 在运行时工作,并且没有您使用的__type 属性。

    要解决此问题,您需要手动将此属性附加到函数。例如:

    let myStrFunc = ((s: string) => `Hello, ${s}!`) as StrFunc;
    myStrFunc.__type = 'StrFunc'
    
    
    let myNumFunc = ((n: number) => `Hello x${n}!`) as NumFunc;
    myNumFunc .__type = 'NumFunc'
    

    现在这两个函数都需要判别式并且应该可以工作。希望对您有所帮助。

    【讨论】:

    • let myNumFunc = Object.assign((n: number) =&gt; `Hello x${n}!`, { __type: 'NumFunc' } as const); let myStrFunc = Object.assign((s: string) =&gt; `Hello, ${s}!`, { __type: 'StrFunc' } as const);
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-10
    • 2021-10-05
    • 2018-11-24
    • 2020-05-07
    • 1970-01-01
    相关资源
    最近更新 更多