microsoft / microsoft/TypeScript
Covariant assignability of type guard functions is unsound
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 111k
- Forks
- 14.3k
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 132
Description
TypeScript Version: master (af8e44a)
Search Terms: user-defined type guard predicate assignable assignability unsound covariant invariant
Code
class A {
a: string;
}
class B extends A {
b: string;
}
function isB(x: {}): x is B {
return x instanceof B;
}
const isA: (x: {}) => x is A = isB; // allowed, should be compile error
const x = <A | string>new A();
if (!isA(x)) {
console.log(x.slice()); // runtime error
}
Expected behavior: Assignability error where marked.
Actual behavior: Successful compilation, runtime error.
Playground Link: link
Related Issues: #24865
If we want a kind of type guard function that is covariant, we need to not narrow when it returns false, i.e., a "true" result would be sufficient but not necessary for the value to be of the tested type. And we'd need a different syntax for the type of a type guard function that is necessary and sufficient compared to a type guard function that is sufficient but not necessary. One idea for the latter is (x: {}) => x is A | false. (A type guard function that is necessary but not sufficient would then be (x: {}) => x is A | true.) Getting all these variants supported would help us support conjunctions and disjunctions of type guard calls with other boolean expressions in #24865. If you like, this issue can be for the removal of the unsound assignability rule and I can file a separate suggestion for the new kinds of type guard functions.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the linked Playground reproduction and the marked assignment of isB to the isA type. Trace how the compiler checks assignability of type predicate functions, using the related issue for context. Done means the assignment produces an error and the demonstrated unsound narrowing is prevented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100