-
Notifications
You must be signed in to change notification settings - Fork 13.2k
Description
⚙ Compilation target
ES2015
⚙ Library
lib.es2015.collection.d.ts
Missing / Incorrect Definition
TypeScript/src/lib/es2015.collection.d.ts
Lines 87 to 90 in d85767a
| /** | |
| * @returns a boolean indicating whether an element with the specified value exists in the Set or not. | |
| */ | |
| has(value: T): boolean; |
I believe
Set<T>.has(value: T): booleanshould become
Set<T>.has(value: unknown): value is TThis applies for other methods as well, such as Map<K, V>.has(key: K): boolean, as well as other ES standards.
Essentially, it's not an error to pass an arbitrary value to Set.has(). It doesn't lead to a crash, exception, or error of any sort, even when we pass weird values like {}, [], or NaN, so the typechecker shouldn't stop us from doing it. We simply get a true if the value is in the Set, or a false if the value is not. And since the Set can only contain values of type T, the boolean returned by Set.has() also becomes proof that value is of type T. This makes it an ideal candidate for a type predicate.
This would immediately fix several regressions in our codebase that we saw when we upgraded TypeScript from 5.3 to 5.5. TypeScript's inferred type predicates are amazing, but they narrowed the types of our Sets and caused several of our Set.has() method calls to become errors. The sample code is a simplified example of what we've found in the wild in our codebase.
Sample Code
declare function defaultAttrs(subtype: string): string[]
declare function getAttrs(): string[]
type MyAttribute = `_${string}`
function isMyAttribute(key: string): key is MyAttribute {
return key.startsWith('_')
}
export function myAttrs(subtype: string) {
const defaults = defaultAttrs(subtype)
return new Set(
Object.keys(defaults).filter((key) => {
return isMyAttribute(key)
}),
)
}
function attrInSet(subtype: string) {
const myAttrSet = myAttrs(subtype)
for (const attr of getAttrs()) {
// Argument of type 'string' is not assignable to parameter of type '`_${string}`'.ts(2345)
if (myAttrSet.has(attr)) {
return true
}
}
return false
}Documentation Link
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/has