0

I run into a problem when trying to generate an object through Array.reduce function. This code will work without any issues in javascript. However in typescript I'm not able to match types from the reduce function and it throws the Error shown below.

This is a small example, in my case there are many more input types and 2-3 levels of processing like the buildSchema function below. I would prefer to generate them through the reduce function rather than manually listing them as seen in the morph object below.

Any idea how I can resolve this through the type system ? To infer the types based on input. So I can still have the type-safety but not have to copy paste the same code over and over just for different input keys ?

Sample Code:


type inputs = "alpha" | "beta" | "gamma";

type AlphaSchema = {
    pet: string,
    house: string
}

type BetaSchema = {
    boss: string,
    work: string,
}

type GammaSchema = {
    monk: string,
    temple: string,
}

// Anything I can try using this type ? Using generics and keyof ?
// <T extends keyof Schemas> => Schemas[T] ?
type Schemas = {
    'alpha': AlphaSchema,
    'beta': BetaSchema,
    'gamma': GammaSchema 
}

type manualMorph = typeof morph

//////////////////////

const morphTypes : ["alpha", "beta", "gamma"] = ["alpha", "beta", "gamma"];

const buildSchema = {
    'alpha' : (str1: string, str2: string): AlphaSchema => { return {pet: str1, house: str2} },
    'beta' : (str1: string, str2: string): BetaSchema => { return {boss: str1, work: str2} },
    'gamma' : (str1: string, str2: string): GammaSchema => { return {monk: str1, temple: str2} }
}

// Manually generated morph object
const morph = {
    'alpha' : buildSchema['alpha'],
    'beta' : buildSchema['beta'],
    'gamma' : buildSchema['gamma'],
}

// Morph from reduce
const morphFromReduce: manualMorph = morphTypes.reduce((acc, type) => {

    acc[type] = buildSchema[type];
    return acc;
}, <manualMorph>{})

Error:

Type '((str1: string, str2: string) => AlphaSchema) | ((str1: string, str2: string) => BetaSchema) | ((str1: string, str2: string) => GammaSchema)' is not assignable to type '((str1: string, str2: string) => AlphaSchema) & ((str1: string, str2: string) => BetaSchema) & ((str1: string, str2: string) => GammaSchema)'.

Type '(str1: string, str2: string) => AlphaSchema' is not assignable to type '((str1: string, str2: string) => AlphaSchema) & ((str1: string, str2: string) => BetaSchema) & ((str1: string, str2: string) => GammaSchema)'.

Type '(str1: string, str2: string) => AlphaSchema' is not assignable to type '(str1: string, str2: string) => BetaSchema'.

Type 'AlphaSchema' is missing the following properties from type 'BetaSchema': boss

I'm using typescript 4.1.3

1 Answers1

1

This will do the job ;)

const morphFromReduce = morphTypes.reduce(<T extends inputs>(acc: manualMorph, type: T) => {
    acc[type] = buildSchema[type];
    return acc;
}, {} as manualMorph);
Tomasz Gawel
  • 8,379
  • 4
  • 36
  • 61
  • 1
    https://stackoverflow.com/users/1010868/tomasz-gawel Thanks a ton ! Been breaking my head for a long time trying to figure out how to get this to work ! I just created an account, so it doesn't let me upvote due to lack of credibility. Will drop by later and upvote it ! – Arvind Kumar Jan 01 '21 at 23:31