gpt4 book ai didi

Typescript - isEmpty 函数的通用类型保护

转载 作者:搜寻专家 更新时间:2023-10-30 21:27:13 24 4
gpt4 key购买 nike

我无法在将提供的值缩小为空对应值的类型约束方面正确实现通用 isEmpty(value)

用例:

function getCountryNameById(countries: LookupItem[] = [], countryId?: number): string | undefined {

if (isEmpty(countries) || !isNumber(countryId)) {

// within this branch I would like to get countries argument to be narrowed to empty array type.
// Same would apply for other function which can have argument type of object or string. Why ? -> to prevent someone to do some mad code hacks like accessing non existent value from empty array ( which would happen on runtime ofc ) on compile time
// $ExpectType []
console.log(countries)

return
}

// continue with code logic ...
// implementation ...
}

约束对象的类似情况:

function doSomethingWithObject( data: { foo: string; bar: number } | object ){ 
if(isEmpty(data)){
// $ExpectType {}
data

// following should throw compile error, as data is empty object
data.foo.toUpercase()

return
}

// here we are sure that data is not empty on both runtime and compile time
}

isEmpty 类型保护实现:

export const isEmpty = <T extends AllowedEmptyCheckTypes>(
value: T | AllowedEmptyCheckTypes
): value is Empty<T> => {
if (isBlank(value)) {
return true
}

if (isString(value) || isArray(value)) {
return value.length === 0
}

if (isObject(value)) {
return Object.keys(value).length === 0
}

throw new Error(
`checked value must be type of string | array | object. You provided ${typeof value}`
)
}

定义类型:

type EmptyArray = Array<never>
type Blank = null | undefined | void

/**
* // object collects {} and Array<any> so adding both {} and Array<any> is not needed
* @private
*/
export type AllowedEmptyCheckTypes = Blank | string | object

/**
* Empty mapped type that will cast any AllowedEmptyCheckTypes to empty equivalent
* @private
*/
export type Empty<T extends AllowedEmptyCheckTypes> = T extends string
? ''
: T extends any[]
? EmptyArray
: T extends object ? {} : T extends Blank ? T : never

这有点奇怪,因为它从类型的角度来看是正确缩小的,但不在 if/else 分支内:

isEmpty for string values

isEmpty for array values

isEmpty for object values

代码可以在这里看到:https://github.com/Hotell/rex-tils/pull/13/files#diff-a3cdcb321a05315fcfc3309031eab1d8R177

相关问题:Type Guard for empty object

最佳答案

处理此问题的一种方法是将空值检查(undefinednull)与空值检查(''[] {})。为此,我倾向于使用两种类型保护 — isDefinedisEmpty

第一个可能看起来像这样。注意 typeof 检查——这使得它也可以处理未声明的变量。

function isDefined<T>(value: T | undefined | null): value is T {
return (typeof value !== 'undefined') && (value !== null);
}

对于空值,可以使用以下模型。

namespace Empty {
export type String = '';
export type Object = Record<string, never>;
export type Array = never[];
}

type Empty =
| Empty.Array
| Empty.Object
| Empty.String;

function isEmpty<T extends string | any[] | object>(subject: T | Empty): subject is Bottom<T> {
switch (typeof subject) {
case 'object':
return (Object.keys(subject).length === 0);
case 'string':
return (subject === '');
default:
return false;
}
}

type Bottom<T> =
T extends string
? Empty.String
: T extends any[]
? Empty.Array
: T extends object
? Empty.Object
: never;

底部值被正确推断。

declare const foo: 'hello' | Empty.String;
declare const bar: [number, number] | Empty.Array;
declare const baz: Window | Empty.Object;

if (isEmpty(foo) && isEmpty(bar) && isEmpty(baz)) {
console.log(foo, bar, baz);
}

编辑:按照建议在 T 上添加约束。

关于Typescript - isEmpty 函数的通用类型保护,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52188387/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com