简体   繁体   中英

Infer object key type from sibling key's value

I have an Object Type Options with two keys:

  1. strategy : a function that requires one parameter of unknown type
  2. parameter : same type as strategy 's first argument

I want to be able to do the following

type FooParameter = { foo: string }
type BarParameter = { bar: string }

const fooOptions: Options = {
  strategy: (parameter: FooParameter) => {},
  parameter: { foo: 'foo' }
}
const barOptions: Options = {
  strategy: (parameter: BarParameter) => {},
  parameter: { bar: 'bar' }
}

The type fooOptions.parameter should be inferred from fooOptions.strategy and barOptions.parameter from barOptions.strategy

Is that possible with TypeScript today?

The only way I can imagine to do this is using a generic type. I think it's unlikely there is a solution where the compiler will check that parameter is a suitable argument for strategy without using a generic type.

type Options<T> = {
    strategy: (parameter: T) => void,
    parameter: T
}

This means that if Options is used in a type annotation then you have to provide a type parameter:

const fooOptions: Options<FooParameter> = {
    strategy: (parameter: FooParameter) => {},
    parameter: { foo: 'foo' }
}

function useOptions<T>(o: Options<T>): void {
    o.strategy(o.parameter);
}

However, anywhere you allow the compiler to infer the type (ie whenever you don't use a type annotation), it is not necessary to provide an explicit type for the generic type parameter. In particular, users of an API such as the useOptions function can pass an object literal, and enjoy the benefits of type-checking and type inference:

useOptions({
    strategy: param => {
        let x = param.x; // Inferred as number
        let y = param.y; // Inferred as string

        // Error: Property 'z' does not exist on type '{ x: number, y: string }'
        let z = param.z;
    },
    parameter: { x: 1, y: 'foo' }
});

Note that the user in this example doesn't have to explicitly write { x: number, y: string } or an equivalent type in order to use the API.

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