使用复杂 "isEmpty" 检查时的类型推断
Type inference when using complex "isEmpty" check
我有以下功能,其工作方式类似于 ramdas isEmpty,但根据我自己的需要量身定制:
/**
* Checks if a value is empty.
* It will return true for the following cases:
* null, undefined, empty string, empty Set, empty Map, an object without properties.
* @param input Can be any value.
* @example
*
* isEmpty([1, 2, 3]); //=> false
* isEmpty([]); //=> true
*
* isEmpty(''); //=> true
*
* isEmpty(null); //=> true
* isEmpty(undefined); //=> true
*
* isEmpty({}); //=> true
*
* isEmpty(new Set([1, 2, 3])); //=> false
* isEmpty(new Set()); //=> true
*
* isEmpty(0); //=> false
*
* isEmpty(new Date()); //=> true
* isEmpty(Date.now()); //=> false
*/
export const isEmpty = (input: any): boolean => {
const isMapOrSet = input instanceof Map || input instanceof Set;
return input === null
|| input === undefined
|| (input instanceof String ? input.length > 0 : false)
|| (isMapOrSet ? input.size === 0 : false)
|| (!isMapOrSet && input instanceof Object ? Object.keys(input).length === 0 : false);
};
使用此函数非常简单,但我对 boolean
return 类型不满意,因为 TypeScript 无法推断此函数提供的空值检查。
例如,以下代码完全没问题,但 TypeScript 会在 someResult[0]
调用时抱怨可能为 null。
const someResult: [] | null = getStuffFromAPI();
const x = isEmpty(someResult)
? {}
: someResult[0]; // TypeScript will complain about a possible _null_ here.
所以问题是:
如何改进函数的签名,以便 TypeScript 可以正确推断 return 类型?
我尝试使用 conditional types 为自定义 return 类型建模,但我不知道如何正确地建模。
为了 100% 清楚我要搜索的内容,这里有一些 伪代码 (请注意 HasNoElements
和 IsEmpty
不存在于 TS):
type IsEmpty<T> =
T extends null | undefined ? true :
T extends Map & HasNoElements ? true :
T extends Set & HasNoElements ? true :
T extends String & IsEmpty ? true :
T extends Object & IsEmpty ? true :
false;
也许我想多了,但我想开阔一下视野。
此问题已通过 TypeScript 3.4 中改进的泛型类型推断得到解决。因此,在我上面的示例中,我基本上获得了 "free".
所需的所有正确类型签名
我有以下功能,其工作方式类似于 ramdas isEmpty,但根据我自己的需要量身定制:
/**
* Checks if a value is empty.
* It will return true for the following cases:
* null, undefined, empty string, empty Set, empty Map, an object without properties.
* @param input Can be any value.
* @example
*
* isEmpty([1, 2, 3]); //=> false
* isEmpty([]); //=> true
*
* isEmpty(''); //=> true
*
* isEmpty(null); //=> true
* isEmpty(undefined); //=> true
*
* isEmpty({}); //=> true
*
* isEmpty(new Set([1, 2, 3])); //=> false
* isEmpty(new Set()); //=> true
*
* isEmpty(0); //=> false
*
* isEmpty(new Date()); //=> true
* isEmpty(Date.now()); //=> false
*/
export const isEmpty = (input: any): boolean => {
const isMapOrSet = input instanceof Map || input instanceof Set;
return input === null
|| input === undefined
|| (input instanceof String ? input.length > 0 : false)
|| (isMapOrSet ? input.size === 0 : false)
|| (!isMapOrSet && input instanceof Object ? Object.keys(input).length === 0 : false);
};
使用此函数非常简单,但我对 boolean
return 类型不满意,因为 TypeScript 无法推断此函数提供的空值检查。
例如,以下代码完全没问题,但 TypeScript 会在 someResult[0]
调用时抱怨可能为 null。
const someResult: [] | null = getStuffFromAPI();
const x = isEmpty(someResult)
? {}
: someResult[0]; // TypeScript will complain about a possible _null_ here.
所以问题是: 如何改进函数的签名,以便 TypeScript 可以正确推断 return 类型?
我尝试使用 conditional types 为自定义 return 类型建模,但我不知道如何正确地建模。
为了 100% 清楚我要搜索的内容,这里有一些 伪代码 (请注意 HasNoElements
和 IsEmpty
不存在于 TS):
type IsEmpty<T> =
T extends null | undefined ? true :
T extends Map & HasNoElements ? true :
T extends Set & HasNoElements ? true :
T extends String & IsEmpty ? true :
T extends Object & IsEmpty ? true :
false;
也许我想多了,但我想开阔一下视野。
此问题已通过 TypeScript 3.4 中改进的泛型类型推断得到解决。因此,在我上面的示例中,我基本上获得了 "free".
所需的所有正确类型签名