The existence of `any`; worse yet, the use of `any` in the standard library.
Mutable arrays are treated as covariant: the classic `cats : Cat[] ; animals: Animal[] = cats; animals.push(dog);` problem.
Methods are both co- and contravariant in their arguments by default, which is comically wrong. Member variables which are functions, meanwhile, are handled correctly.
`readonly` is a lie:
const test: {readonly a: number } = {a: 0}
const test2: {a: number} = test
test2.a = 5
`Record<string, string>` is actually `Record<string, string | undefined>`. There's no way for an interface to specify that it really does return a value at any string index (e.g. for a map with a default value).
`{...object1, ...object2}` is typed as the intersection `typeof object1 & typeof object2`, which is not correct.
const a: {a: 5} = {a: 5}
const b: {a: 4} = {a: 4}
const spread = <L, R>(l: L, r: R): L & R => ({...l, ...r})
const impossible: never = spread(a, b)
You have to resort to bizarre conditional type hackery to control when unions distribute and when they don't.
You can constrain generics as `<T extends string>foo(t: T) => ...` but not `<string extends T>foo(t: T) => ...`, which makes many functions (e.g. Array.includes) much too strict about what they accept.
The existence of `any`; worse yet, the use of `any` in the standard library.
Mutable arrays are treated as covariant: the classic `cats : Cat[] ; animals: Animal[] = cats; animals.push(dog);` problem.
Methods are both co- and contravariant in their arguments by default, which is comically wrong. Member variables which are functions, meanwhile, are handled correctly.
`readonly` is a lie:
`Record<string, string>` is actually `Record<string, string | undefined>`. There's no way for an interface to specify that it really does return a value at any string index (e.g. for a map with a default value).`{...object1, ...object2}` is typed as the intersection `typeof object1 & typeof object2`, which is not correct.
You have to resort to bizarre conditional type hackery to control when unions distribute and when they don't.You can constrain generics as `<T extends string>foo(t: T) => ...` but not `<string extends T>foo(t: T) => ...`, which makes many functions (e.g. Array.includes) much too strict about what they accept.