typescript - 如何键入此合并功能?
问题描述
我对 TypeScripts 或其他类型语言中标准类型以外的任何东西都比较陌生,我正试图找出一种输入这个函数的好方法。我想摆脱参数和返回类型的任何类型。
该函数返回第一个不为 null、未定义或 NaN 的值。
/** returns the first not-null value excluding NaN */
const coalesce = (...args: any): any => {
for (let i = 0; i < args.length; i++) {
// args[i] === args[i] is to avoid NaN, because NaN !== NaN
if (args[i] != null && args[i] === args[i]) {
return args[i];
}
}
return null;
};
这是你将如何使用它:
test('coalesce returns the first value that is not null, undefined, NaN', () => {
expect(coalesce(null, undefined, NaN, 'maybe')).toBe('maybe');
}); // -> passes
解决方案
最简单的版本是捕获我们在一个类型中传递的参数类型的类型,作为所有参数类型的联合返回。
我们可以在剩余参数中使用元组来将所有参数的类型捕获为元组类型,并通过类型查询 来获取元组中所有类型的联合:
const coalesce = <T extends any[]>(...args: T): T[number] => {
for (let i = 0; i < args.length; i++) {
// args[i] === args[i] is to avoid NaN, because NaN !== NaN
if (args[i] != null && args[i] === args[i]) {
return args[i];
}
}
return null;
};
// o is string | number | null | undefined under strict null checks
// T is [null, undefined, number, string] so T[number] is string | number | null | undefined
let o = coalesce(null, undefined, NaN, 'maybe')
现在这个函数的重点是删除 null 和 undefines(还有NaN
s ,但它们没有在类型系统中建模,因此与这些无关)。当前签名在类型中留下了null
和undefined
。我们可以添加一些映射类型和条件类型来移除null
and undefined
if 任何一个参数不能是null
or undefined
(好像一个参数不是null
或者undefined
它会被返回)
type ExcludeNullIfAnyNotNullHelper<T> = {
[P in keyof T]-?: (null extends T[P] ? never : null) |
(undefined extends T[P] ? never : undefined)
}[keyof T]
type ExcludeNullIfAnyNotNull<T extends any[]> = Exclude<T[number], ExcludeNullIfAnyNotNullHelper<T>>
type t1 = ExcludeNullIfAnyNotNull<[null, undefined, number, string]> // number | string
type t2 = ExcludeNullIfAnyNotNull<[null | string, string]> // string
type t3 = ExcludeNullIfAnyNotNull<[null | undefined | string, string]> // string
type t4 = ExcludeNullIfAnyNotNull<[null | undefined | string, string | null]> // string | null
type t5 = ExcludeNullIfAnyNotNull<[null | undefined | string, string | undefined]> // string | undefined
type t6 = ExcludeNullIfAnyNotNull<[null| undefined | string, string | undefined, number]> // string | number
function coalesce<T extends any[]>(...args: T): ExcludeNullIfAnyNotNull<T>
function coalesce<T extends any[]>(...args: T): T[number] {
for (let i = 0; i < args.length; i++) {
// args[i] === args[i] is to avoid NaN, because NaN !== NaN
if (args[i] != null && args[i] === args[i]) {
return args[i];
}
}
return null;
};
// o is string | number
let o = coalesce(null, undefined, NaN, 'maybe')
推荐阅读
- javascript - 使用 Chrome 扩展覆盖 Element.prototype.attachShadow
- javascript - React useEffect 导致:无法对未安装的组件执行 React 状态更新
- c# - 每次我从矩形数组中删除一个项目时都会出现异常
- browser - 浏览器扩展可以访问我的脚本中的本地范围变量吗?
- .net - 构造函数中的这个参数如何直接在 FSharp 中的成员方法中使用?
- ruby - 有没有办法为 Chef 资源的 name 属性指定默认值?
- command - 将文件从 1 移动到不同的文件夹
- vba - MSAccess 2010 VBA 打开只读数据库
- r - inf_mr 不使用 xaringan 幻灯片刷新
- php - PHP Oracle 更新表错误 - oci_execute ORA-00933