Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
255 views
in Technique[技术] by (71.8m points)

typescript - Issues with Types when using reduce on an object

I have a function trying to return an object it receives with the keys all Pascal case instead of Camel case.

My Interfaces:

export interface INodeMailerResponseLower {
    accepted: string[];
    rejected: string[];
    envelopeTime: number;
    messageTime: number;
    messageSize: number;
    response: string;
    messageId: string;
}

export interface INodeMailerResponseUpper {
    Accepted: string[];
    Rejected: string[];
    EnvelopeTime: number;
    MessageTime: number;
    MessageSize: number;
    Response: string;
    MessageId: string;
}

My Code:

import { upperFirst } from 'lodash';

const response: INodeMailerResponseLower;   // << insert object values here
const formattedResponse: INodeMailerResponseUpper = Object.keys(response).reduce((acc, key) => {
     acc[upperFirst(key)] = response[key];
     return acc;
   }, {});

Typescript is giving me the following error message:

Type '{}' is missing the following properties from type 'INodeMailerResponseUpper': Accepted, Rejected, EnvelopeTime, MessageTime, and 3 more.ts(2740)

Question: How do I correctly type my accumulator when doing the reduce?

question from:https://stackoverflow.com/questions/65910384/issues-with-types-when-using-reduce-on-an-object

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Use Partial<INodeMailerResponseUpper> for the reduce type parameter. This will mean acc has that type and will allow you to assign properties to it. However, you need to cast the result to INodeMailerResponseUpper because TypeScript doesn’t know that the final result will contain all the required properties.

You could do it like this, which uses a fair bit of type assertions:

const formattedResponse = Objectkeys(response)
    .reduce<Partial<INodeMailerResponseUpper>>((acc, key) => {
        (acc[upperFirst(key) as keyof INodeMailerResponseUpper] as unknown) =
            response[key as keyof INodeMailerResponseLower];
        return acc;
    }, {}) as INodeMailerResponseUpper;

Or you could also improve the type of lodash’s upperFirst (using TypeScript 4.1):

declare module 'lodash' {
    interface LoDashStatic {
        upperFirst<S extends string = ''>(string?: S): Capitalize<S>;
    }
}

const formattedResponse = (Object.keys(response) as (keyof INodeMailerResponseLower)[])
    .reduce<Partial<INodeMailerResponseUpper>>((acc, key) => {
        // Without the as unknown, TypeScript would complain that
        // string | number | string[] is not assignable to undefined
        (acc[upperFirst(key)] as unknown) = response[key];
        return acc;
    }, {}) as INodeMailerResponseUpper;

Unfortunately, there isn’t a way to completely avoid type assertions.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...