具有无点函数的通用类型

Generic types with point-free functions

假设我有下一个功能:

function cast<T>(v: any): T {
    return v as T;
}

现在,我有一个数组,我想使用 map 投射:

const arr = [1, 3, 5];

// works
arr.map(value => cast<number>(value));

// but I want
arr.map(cast<number>);

可能吗?我可以在无点地图上传递通用吗?

你想要的是不可能的,因为 cast<number> 不被视为数组映射所需的回调函数。

您可以通过简单地在控制台中记录它们来尝试查看什么是函数,什么不是函数。

尝试console.log(cast) 并且 console.log(cast<number>)

实际上,数组原型中的方法map是通用的。

Array<T>.map<U>(callback: (value: T, index: number, array: T[]) => U): U[]

因此,通过将您的 cast 函数与任何类型参数一起使用(例如将其用作无指针)returns unknown。完全符合预期。

你可以像这样投射你的数组

const arr = [1, 3, 5];
const re = arr.map<string>(cast);

Here 关于这个很有趣 post。


我 post 几个月后读到这篇文章时,另一个想法突然闪过我的脑海。
另一个解决方案可能是一个函数包装器,用于将类型参数显式传递给 cast 函数。

type Fn<T> = (element: any) => T;

const cast = <T>(element: any): T => {
    return element as T;
}

const caster = <T>() => {
    return cast as Fn<T>;
}

const dut: any[] = [1, 2, 3, 4, 5, 6];
const casted = dut.map(caster<number>());

// casted is of type number[]

虽然主要解决方案仍然是最好的,但这种方法可以解决一些目标 API 不提供任何重载来推断类型的情况。

希望对您有所帮助。

使用无点样式的更多类型安全替代方案(Fail-Fast 运行-时间检查):

function assert(expr: unknown, msg = ""): asserts expr { if (!expr) throw Error(msg); }
const every = <T>(cb: (t: unknown) => t is T) => (a: unknown[]): a is T[] => arr.every(cb);
const isNumber = (mn: unknown): mn is number => typeof mn === "number"

const arr: unknown[] = ... // given some unknown array
assert(every(isNumber)(arr));
arr // arr now of type number[] (or has thrown, which could be fetched by an error handler)

Playground sample