0

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.

3
  • Assign element type to declared array type. See explanation below why this is not working Commented Jul 6, 2020 at 6:38
  • Imaging that const fn = (str: string) => str.endsWith('test') : str : '' . Now if assignment would be allowed, you could do fnArr[0](123) which will cause runtime error because number doesn't have endsWith method Commented Jul 6, 2020 at 9:12
  • thank you @Aleksey. BTW the articele might help.stephanboyer.com/post/132/… Commented Jul 6, 2020 at 9:51

1 Answer 1

1

So the actual question here is why

(val: string) => string

is not assignable to

(val: string | number) => string | number

That's because the former can't handle arguments of type number

To check if x is assignable to y, we first look at the parameter list. Each parameter in x must have a corresponding parameter in y with a compatible type.

More info on function types compatibility here.


So one possible solution would be declaring array that that can accept functions of type
(val: string) => string or functions of type (val: number) => number

const fnArr: (Fn<string> | Fn<number>)[] = []

const fn = (str: string) => str

fnArr.push(fn) // is ok now

Playground

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.