我试图通过使用更严格的规则集皮棉收紧了我的TS码,但我有什么应该是充满活力的合法用途挣扎。
我正在做一个守护型检测,如果事情是迭代(将其包装在一个数组,如果没有),我不知道该怎么告诉TS除了抑制皮棉规则告诉这是犹太:
function isIterable(obj: any): obj is Iterable<unknown> {
return obj && typeof obj[Symbol.iterator] === 'function';
}
我想这更改为:
function isIterable(obj: undefined | {[Symbol.iterator]?: unknown}): obj is Iterable<unknown> {
return !!obj && typeof obj[Symbol.iterator] === 'function';
}
这编译没有使用any
,但它不是很有用,因为我想未知类型的值传递给它。
有没有说“是的,我确实想依靠JS返回undefined
访问并不在对象上存在的属性”的“干净”的方式? ESP。因为这是一种写作类型警卫整点。
我不知道如果事情一样,没有不安全的,任何你买太多user-defined type guard里面执行,因为通常这种类型的后卫整点是让编译器缩小值不能正常通过做内置的控制流变窄。我当然会理解的悬挂这样的实现内部棉绒规则。
但我认为你可以得到近你正在寻找这样的行为:
function isIterable(obj: unknown): obj is Iterable<unknown> {
if ((typeof obj !== 'object') || (obj === null)) return false;
// obj is now type object
const wObj: { [Symbol.iterator]?: unknown } = obj; // safely widen to wObj
return typeof wObj[Symbol.iterator] === 'function';
}
那几个跳铁圈通过,但这个想法是使用控制流变窄缩小unknown
到object
,然后扩大object
具体的类型,然后再尝试检查一个可选属性(这种情况通过引入新的变量)。最后,检查加宽类型属性的类型。既然你正在检查的属性键是一个符号类型,你需要在加宽型提及的特定属性的名称。如果属性键是一个字符串,你可以逃脱使用string index signature:
function isPromise(obj: unknown): obj is Promise<unknown> {
if ((typeof obj !== 'object') || (obj === null)) return false;
// obj is now type object
const wObj: {[k: string]: unknown} = obj; // safely widen to wObj
return typeof wObj.then === 'function';
}
无论如何,我希望让你更接近你的目标。祝好运!
另外一个很好的策略是与Partial
投用as
。
interface RegularForm {
regular: number;
}
interface FancyForm extends RegularForm {
fancy: string;
}
const isFancyForm = (instance: RegularForm): instance is FancyForm =>
(instance as Partial<FancyForm>).fancy !== undefined;