简体   繁体   中英

Typescript: use specific extended interface to satisfy generic “extends” type argument?

Here's a small code example (side note: I'm running Typescript v3.8.3):

interface IOptions<T> {
  arg: T;
}

interface IExtraOptions extends IOptions<number> {
  arg2: string;
}

type Func = <T, OptionsT extends IOptions<T>>(options: OptionsT) => T;

const f: Func = (options: IExtraOptions): number => {
  return options.arg2 === 'dev' ? 0 : options.arg;
};

I would expect this to work, because IExtraOptions extends IOptions and would thus satisfy the OptionsT extends IOptions<T> constraint, but I get:

Type 'OptionsT' is not assignable to type 'IExtraOptions'.

Property 'arg2' is missing in type 'IOptions' but required in type 'IExtraOptions'.ts(2322)

Removing the OptionsT argument altogether and just using IOptions<T> as the type argument for "options" gives the same error. Replacing "number" with a non-default type doesn't fix it either. Anyone know what I'm doing wrong?

If you have a generic function, the generics type parameters of the function are for the caller to determine, not for the implementation to fix as some arbitrary types. For example given your example, this call would be valid f<boolean, IOptions<boolean>>({ arg: true }) and the implementation you specified does not return an object to satisfy those type parameters.

The conclusion is that if you have a generic function, generally nothing but a generic function will satisfy as the implementation (although using very loose types such as any , never or unknown might also work).

If you want to create specialized functions, don't use a generic function, use a generic type that happens to be a function:


type Func <T, OptionsT extends IOptions<T>> =(options: OptionsT) => T;

const f: Func<number, IExtraOptions> = (options ) => {
  return options.arg2 === 'dev' ? 0 : options.arg;
};

Playground Link

Also you can derive T from TOptions to simplify things a bit:


type Func <OptionsT extends IOptions<any>> =(options: OptionsT) => OptionsT['arg'];

const f: Func<IExtraOptions> = (options ) => {
  return options.arg2 === 'dev' ? 0 : options.arg;
};

Playground Link

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM