javascript - How can I infer an object property's value in TypeScript when using mapped types? - Stack Overflow

I'm trying to create a singleton factoryLookup in typescript that enforces that I have a factory d

I'm trying to create a singleton factoryLookup in typescript that enforces that I have a factory defined for every value in a union type (i.e. a mapped lookup type), however I also want to be able to infer the signature (could be a value or function of arbitrary arguments) for any value that is looked up. Here is a code sample:

// Using a simple object, I can create a map between a key and an arbitrary function or value
const factoryLookup = {
  foo: (message: string, count: number): string => message + count,
  bar: (): number => 1,
};

// TypeScript can infer function signature of the foo and bar values
factoryLookup.foo('hello world', 3); // foo's signature: (message: string, count: number) => string
factoryLookup.bar(); // bar's signature: () => number

type FactoryTypes = 'foo' | 'bar' | 'baz';

// With a mapped type, TypeScript can enforce I have *something* defined for every member I am mapping
const typedFactoryLookup: { [key in FactoryTypes]: any } = {
  foo: (message: string, count: number) => {},
  bar: () => {},
  baz: (obj: any) => {},
};

// However, I don't know how to infer the mapped values
typedFactoryLookup.foo; // any type
typedFactoryLookup.bar; // any type
typedFactoryLookup.baz; // any type

I want the type safety of ensuring I have a function defined for every value in my union/enum type, but also the type inference to know what the signature of that value is.

Any ideas on how to solve this, or alternative approaches that achieve the same goals would be appreciated.

I'm trying to create a singleton factoryLookup in typescript that enforces that I have a factory defined for every value in a union type (i.e. a mapped lookup type), however I also want to be able to infer the signature (could be a value or function of arbitrary arguments) for any value that is looked up. Here is a code sample:

// Using a simple object, I can create a map between a key and an arbitrary function or value
const factoryLookup = {
  foo: (message: string, count: number): string => message + count,
  bar: (): number => 1,
};

// TypeScript can infer function signature of the foo and bar values
factoryLookup.foo('hello world', 3); // foo's signature: (message: string, count: number) => string
factoryLookup.bar(); // bar's signature: () => number

type FactoryTypes = 'foo' | 'bar' | 'baz';

// With a mapped type, TypeScript can enforce I have *something* defined for every member I am mapping
const typedFactoryLookup: { [key in FactoryTypes]: any } = {
  foo: (message: string, count: number) => {},
  bar: () => {},
  baz: (obj: any) => {},
};

// However, I don't know how to infer the mapped values
typedFactoryLookup.foo; // any type
typedFactoryLookup.bar; // any type
typedFactoryLookup.baz; // any type

I want the type safety of ensuring I have a function defined for every value in my union/enum type, but also the type inference to know what the signature of that value is.

Any ideas on how to solve this, or alternative approaches that achieve the same goals would be appreciated.

Share Improve this question asked Aug 8, 2018 at 15:14 Craig SmithamCraig Smitham 3,9834 gold badges35 silver badges43 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 7

If you explicitly type a variable, that will be its type no inference will occur. You can get the behavior you want, but you need to use the inference behavior of functions.

type FactoryTypes = 'foo' | 'bar' | 'baz';


function createTypedFactoryLookup<T extends { [key in FactoryTypes]: any }>(factory: T) {
    return factory;
}
const typedFactoryLookup = createTypedFactoryLookup({
    foo: (message: string, count: number) => {},
    bar: () => {},
    baz: (obj: any) => {},
})

typedFactoryLookup.foo; // (message: string, count: number) => void
typedFactoryLookup.bar; // () => void
typedFactoryLookup.baz; // (obj: any) => void

You can also create a version that takes in the type for the keys, but you will need to use a function that returns a function as typescript does not support specifying only some type parameters (it might be supported in 3.1)

function createTypedFactoryLookup<TKeys extends string>(){
    return function <T extends { [key in TKeys]: any }>(factory: T) {
        return factory;
    }
}
const typedFactoryLookup = createTypedFactoryLookup<FactoryTypes>()({
    foo: (message: string, count: number) => {},
    bar: () => {},
    baz: (obj: any) => {},
})

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744606998a4583527.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信