在Typescript中,我如何编写一个curried函数,从第一个参数限制和推断输出类型?

b4wnujal  于 2023-04-22  发布在  TypeScript
关注(0)|答案(2)|浏览(101)

我对Typescript比较陌生,想知道:对于简单的curried函数,如:

const add = (a:number) => (b:number):number => a + b;

是否可以同时支持数字和字符串输入,并将输出类型限制为第一种输入类型?
例如:

const add = (a:number | string) => (b:type of a):type of a => a + b;
w3nuxt5m

w3nuxt5m1#

是的,但我认为你在函数的实现中被类型Assert所困扰。但我们可以精确地确定类型。
乍一看,你会“只是”使用一个泛型类型参数(playground链接):

const add = <T extends number | string>(a: T) => (b: T): T => {
    // ...implementation...
};

实际上,这对于以下情况很有效:

let a = 1;
let b = 2;
console.log(add(a)(b));

但是,如果在调用add函数时使用文字,则不起作用:

console.log(add(1)(2));
//                 ^−−−−− Error here

问题是T被推断为文字类型1,而不是number
您可以通过使用Map类型扩展它来解决这个问题:

type Widen<T extends number | string> = T extends number ? number : string;

const add = <T extends number | string>(a: T) => (b: Widen<T>): Widen<T> => {
    // ...implementation...
};

现在,所有这些工作:

let a = 1;
let b = 2;
console.log(add(a)(b));     // <== Works

console.log(add(1)(2));     // <== Works
console.log(add("x")("y")); // <== Works

但这些并没有,正如所期望的:

console.log(add(1)("y")); // <== Error as desired, can't use string for second function arg
console.log(add("x")(2)); // <== Error as desired, can't use number for second function arg

那么我在上面方便地忽略的“实现”呢?不幸的是,a + b不起作用,因为TypeScript不太明白你可以可靠地将+应用于这些参数。但是你知道你可以,所以你可以通过类型Assert来解决它:

return (a as any) + (b as any);

我不喜欢类型Assert,并尽可能避免then,但我不知道用上面的方法来避免它。

omqzjyyz

omqzjyyz2#

通常你需要一个generic type parameter,像这样:

const equals = <T,>(x: T) => (y: T) => x === y;

这里的<T,>声明了一个泛型类型参数。需要,来避免带有JSX组件的文件中的语法歧义,但如果您不使用这些组件,则可以删除逗号。
对于您的示例,您希望将类型约束为string | number,因此您需要type参数的上限:

const add = <T extends string | number>(x: T) => (y: T) => x + y;

Playground链接
另一种方法,如果你只想使用几个已知类型,并且你不需要完全的泛型,那就是使用函数重载:

function add(x: string): (y: string) => string;
function add(x: number): (y: number) => number;
function add(x: string | number) {
    return (y: string | number) => x + y;
}

Playground链接
对于您的特定示例,有一个问题,因为TypeScript认为如果您编写一个+,这可能意味着数字加法或字符串连接,这取决于运行时的类型,这可能是一个错误。所以在这些片段中,你会得到一个类似 “Operator '+' cannot be applied to types 'T' and 'T'" 的错误。一般来说,这是一个很好的策略,因为通常您肯定想要加法而不是串联,反之亦然。
我认为你的函数只是一个简单的例子,模糊地添加字符串或数字超出了你的问题的范围。但是如果有问题,请参阅here修复这个错误。

相关问题