类型保护是我发现的少数几个地方之一any
是完全可以接受的。根据参数的不同,您基本上有两种类型的类型保护
- 他们需要很多东西,通常是一个联合(例如,
A | B | C
)并缩小联合范围(例如,B
).
- 他们拿了一些不为人知的东西这是什么并赋予它形状。
在前一种情况下,您可以轻松地在类型系统的范围内工作以缩小范围。
在后一种情况下,您需要处理不同程度的“无形状”,但在极端情况下(例如您的unknown
)你没有类型支持,这会导致看起来有点难看。看这里:
type HasProp<T extends object, K extends string> = T & {[P in K]: unknown};
/*
* type guard to ensure that an arbitrary object has a given property
*/
function hasProp<T extends object, K extends string>(obj: T, prop: K): obj is HasProp<T, K> {
return prop in obj;
}
function isErrorEvent( e: unknown ): e is ErrorEvent {
if( !e ) return false;
if (
typeof e === "object" && //type guard determines `e` is `object | null`
e !== null //type guard to narrow down `e` to only `object`
) {
if (
hasProp(e, "colno") && //type guard to add `colno` to the properties known to be in `e`
hasProp(e, "error") && //type guard to add `error` to the properties known to be in `e`
hasProp(e, "lineno") && //type guard to add `lineno` to the properties known to be in `e`
hasProp(e, "message") //type guard to add `message` to the properties known to be in `e`
){
return (
typeof e.colno === 'number' &&
typeof e.error === 'object' &&
typeof e.lineno === 'number' &&
typeof e.message === 'string' &&
e.message.length > 0
);
}
}
return false;
}
我想清楚 - 这段代码所做的所有操作都是correct。您无法检查是否e
如果它不是对象,则具有一些任意属性。如果不检查属性是否存在,则检查任意属性值是否为给定类型是没有用的。
话虽如此,它过于冗长而且有点迟钝。
- The
e !== null
没有用,因为它已经被处理了!e
在一开始的时候。
- 检查属性是否存在以检查其值是否为数字与检查值是否为数字直接等效。通常没有区别 - 如果属性不存在,其值是不同的类型,那么最终都是相同的。
因此,我个人很乐意输入e
as any
。如果你想在两者之间达成妥协some类型安全并且编写的代码较少,那么您可以将其用作Record https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeystype
function isObj(obj: unknown): obj is Record<PropertyKey, unknown> {
return typeof obj === "object" && obj !== null;
}
function isErrorEvent( e: unknown ): e is ErrorEvent {
if ( isObj(e) ) {
return (
typeof e.colno === 'number' &&
typeof e.error === 'object' &&
typeof e.lineno === 'number' &&
typeof e.message === 'string' &&
e.message.length > 0
);
}
return false;
}
游乐场链接 https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABDAzgeQEYCsAUdsBci4A1mHAO5gCUR+WyKiASgKYRwBOAJgDwAKnOAAdWnKAE8A0qwkAaYmDKUwAPkQBvAFCJdiTqyghOSSaLjBE9RAF47iAET12UB4gBk7q9kQBCe2AgADZBANxaAL5aWqCQsAiMAKKcQpyJAG6sYFA4iKxEpORUiLR5jIjJqRlZUJo6ejCWuaiYuKzUJXV63fqGxkg49T09ZqwWeQB0HEHkunY2iADkgQC2GGKLHu5Dw3qj46wTYqlz9ovO0JueO7uI+5aHQTBgWXC2Z6vrnFfbt903u3ukxWrBQKAAhgBzVjvBaLFBQTjPSE-AHDQ4gsFQx5ZSFQAAWiHUAAY0SVwt0ojsDEYTIhgOCgihWOEIkA
对我来说,上面的代码更容易阅读和理解。它没有经过编译器严格检查,但也是完全正确的。这也是使用时的行为完全相同any https://www.typescriptlang.org/play?#code/C4TwDgpgBA8gRgKwgY2AaQiKBeKBnYAJwEsA7AcygB8pSBXAWzgkOvxCYHsAbAbgCh+AMzqlUxTqSjE88BAApOiAFxRRAa1KcA7qQCUqpQml4oAQ1JYA3lAD0tgDwBaF09qdg5qACUUnQgAm-FAhUIQQwHSEUqCQnEJQRjjYuABERijAqVAAZDmJiFAAhCm0dNx8-AC+giJiwBJSMgCihIT+zQBuEKTA8lAQqhpaulAGAyZQre2EXT2eVsGhxAn9MnLyEHpjUIuh+2ERUVLySwcHsRDxAwB0yDxaISm4AOT0TCwvuTln56GX1wgNxYMyepReGVQXzyvz+UABCSB3DIPU4yVe72YhGhPzh+1hfwRtwYEDweDM5GgzygLwIJAoOIJ5yBJLJFKRPXIwAAFlAAHxQAAMTLGAn2NV+4Ui0SgQjM3DwEAEVSAA这就是为什么我不反对它。只要你对你拥有的对象进行适当的检查,它是否存在就无关紧要了Record
or any
。无论哪种方式,您都不会从编译器获得任何类型支持。后者在类型方面稍微正确一些,但这是否会产生影响取决于您。
注1:您还可以使用类型断言e as Record<PropertyKey, unknown> https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABDAzgUQE4bhtA3AUzCgApECAuRcAazDgHckBKKg5FRTbXQ4xAN4AoRKOTBEZdgDJpiKAE8ADgTgT2AXi2IARHABGAKwLQdiZoJFjrEBCiiIDhxBvKIAhpwBKJnABMAHgAFbBUMRQBpAgUAGmowOkYwAD4AbitrUQwCKBAMJBIMzOtFFTVHIwA6WwAbelEtVwByMBAAW30CDCbEWSLi0VLVCSdKrp4G7SanEygevoHMofLRmpgwIjgXKdaOrvnpfoGj4uWRqraCFBR3AHNNKfsMdduDk8zRy+u7gkqaoluUAAFohkogAAzvZjpawAXyERWyuXyiGA7hqKAI6VhQA。没什么大不了的,但是额外的isObj
类型保护似乎更有可能被重用。
注 2:仅供记录,hasProp
可以更改以应用于多个属性。它并没有解决我在类型保护中使用它所遇到的核心问题,但它在其他地方可能仍然有用:
/*
* type guard to ensure that an arbitrary object has a given properties
*/
function hasProps<T extends object, K extends PropertyKey>(obj: T, ...props: K[]): obj is HasProp<T, K> {
return props.every(prop => prop in obj);
}
/* ... */
if (hasProps(e, "colno", "error", "lineno", "message")) { //type guard to add `colno`, `error`, `lineno`, `message` to the properties known to be in `e`
/* ... */
游乐场链接 https://www.typescriptlang.org/play?#code/C4TwDgpgBAEghgZwAoCcD2YA8AVKEAewEAdgCYJRoBGAVhAMbAA0UA0noSeVKhhCqFYQQAPigBeKLgBkUAN4BtJFACWxNgF0AXFACuxANbE0Ad2IBfANwAoawHoAVNagOooSFADmuuClJu0PGIEXRRoYAALOGAoOHVfKhVgFF8QSloGGKiKOC8VADcSKDB0SAEQZwc7awAzfUYVNHVs3jAEHA4iMgpqOkYWdgIu7lb+QWERAApenWwWADpFkowEHVYFDQBKHV7VCnhkUpwBsTlnKAuw4FD1Zbb5iEKUEEm7iTE3tXSaTZtzWzqxAaTT2AFEUOgUKDCsRgJM8Dp9EZTOptng9lBwZDoSQYmcLhcVDV4QBCaCbKBXG5QGpwAA2CAgNgJUHOhJqUEmbJZbnAEDQHOg4mFUAARL1MqKoNJZHY7O5oN5fP5SBAiCgALZqCAUAAGEF1GN1EsYUAAPlBiLo6XTddyWdASSKrTaeW6WXKFV4fH4ApbfOgTFBSCioPrDcBAk06WljRlGHaWRT8e6iZyWqUEJMICxRfQ0HTjKLc-xIcWxXTtUXcxqdQg4J4IKLNsmoJ6+d7lX64KR-Lr84W0LqWPqIWgUMOw5XiCQhyPawh642I4FItA7mMVDqoMizH6qNAvuH7e6WVSUOouafrwSFQK8PMB8YLsLJAByK0ag8oN-S6Qnm8WTvQUHjHFAXxFN8TWAX8ZQAwCLmAh9p1nCRIM-b9YP-BDT3ghCkIgeYFyXIVIIQZI1E8LC8MAwjiIbQi6RITxIigMQAAYaLdX54P+Fk+IJc91FpBkmWscwgA