The code is simple
// it is ok because type 'string' is assignable to type 'string | number'
const arr:Array<string|number> = []
arr.push('foo')
But I got error with the following code.
interface Fn<T> {
(val: T): T
}
const fnArr:Fn<string|number>[] = []
const fn = (str:string)=>str
//error
fnArr.push(fn)
and the error shows:
Argument of type '(str: string) => string' is not assignable to parameter of type 'Fn<string | number>'.
Types of parameters 'str' and 'val' are incompatible.
Type 'string | number' is not assignable to type 'string'.
Type 'number' is not assignable to type 'string'.(2345)
the logic seems to be opposite. the fnArr is declared as an array whose elements are functions with string or number parameters, so it is valid to push a function with string parameter.I thought 'string' is assignable to type 'string | number', but why the error shows Type 'string | number' is not assignable to type 'string'.
what is the rules when TS process array element type checking? assign element type to declared array type or assign declared array type to the element type?
Edit:
After read doc mentioned by @Aleksey, I still feel a little confused. I mean, the function
(val: string | number) => string | number
has parameter val with type string or type number, I thought it has a larger scale than the function only has paramter with type string. just like an analogy. I thought type number extends typenumber | string. so I thought there shouldn't be any error with code above
In the contrary, as @Aleksey said, the function
(val: string | number) => string | number
can handle arguments of type number and type string, but the function (val: string) => string can't handle arguments of type number, I think he is correct.
so I still feel confused.
const fn = (str: string) => str.endsWith('test') : str : ''. Now if assignment would be allowed, you could dofnArr[0](123)which will cause runtime error because number doesn't haveendsWithmethod