Typescript: bind function no overload matches this call

This is my code:

type FormState = "email" | "password" | "whatever";

const f = <
  T extends FormState,
  K extends keyof T
>(
  fieldName: K,
  fieldValue: T[K],
  hasErrors?: boolean
) => {}

f.bind(null, "email"); // <-- This gives error

I'm unable to change neither the type nor the function, how can I use bind here?

This is a link to the typescript playground.

The log of the error is:

No overload matches this call.
  Overload 1 of 6, '(this: (this: null, arg0: number | ... 42 more ... | "padEnd", fieldValue: string | ... 42 more ... | ((maxLength: number, fillString?: string | undefined) => string), hasErrors?: boolean | undefined) => void, thisArg: null, arg0: number | typeof iterator | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | ... 31 more ... | "padEnd"): (fieldValue: string | ... 42 more ... | ((maxLength: number, fillString?: string | undefined) => string), hasErrors?: boolean | undefined) => void', gave the following error.
    Argument of type '"email"' is not assignable to parameter of type 'number | unique symbol | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | ... 28 more ... | "padEnd"'.
  Overload 2 of 6, '(this: (this: null, ...args: "email"[]) => void, thisArg: null, ...args: "email"[]): (...args: "email"[]) => void', gave the following error.
    The 'this' context of type '<T extends FormState, K extends keyof T>(fieldName: K, fieldValue: T[K], hasErrors?: boolean | undefined) => void' is not assignable to method's 'this' of type '(this: null, ...args: "email"[]) => void'.
      Types of parameters 'fieldName' and 'args' are incompatible.
        Type '"email"' is not assignable to type 'number | unique symbol | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | ... 28 more ... | "padEnd"'.

Upvotes: 0

Views: 291

Answers (2)

hoangdv
hoangdv

Reputation: 16147

K extends keyof T and T extends FormState mean K will get 0, 1, or 2 ... as value.

Then your f function will look like this:

const f = (fieldName: number, fieldValue: string, hasErrors?: boolean) => {}

// and to bind f you have to bind a number as the second parameter
f.bind(null, 0);

But, I guess it is not what you want, I think you need the fieldName is FormState. Just try to update the type of fieldName to T instead of K

const f = <T extends FormState, K extends keyof T>(fieldName: T, fieldValue: T[K], hasErrors?: boolean) => {}

f.bind(null, "email");

Upvotes: 1

sno2
sno2

Reputation: 4213

It looks like you are using the wrong types because you are doing keyof FormState is the same as doing keyof string which just gives you the string methods. Perhaps you should limit your function to a single parameter or enhance your types?

type FormState = "email" | "password" | "whatever";

const f = <T extends FormState>(fieldName: T, hasErrors?: boolean) => {}
f.bind(null, "email");

playground

Upvotes: 0

Related Questions