Home > Net >  Renaming a field in a type in Typescript
Renaming a field in a type in Typescript

Time:01-22

I have a type and I would like to create another type from it in which one field is renamed to another. E.g., I have a type like

    type A = {
      name: 'A'
      A: number
    }
    
    type B = {
      name: 'B'
      B: number
    }
    
    type Before = A | B

and I want to rename the field name in Before to name2.

At first. I thought about something like

type After = Omit<Before, 'name'> & { name2: Before['name'] }

const a: After = {
    name2: 'A'
    A: 2
}

This is also the answer I saw in some similar question here.

But then I get an error when defining a.

Type '{ name2: "A"; A: number; }' is not assignable to type 'After'.
  Object literal may only specify known properties, and 'A' does not exist in type 'After'.(2322)

CodePudding user response:

I think it's a distribution problem, which we can solve one of two ways:

  1. With a mapped type
  2. By working directly from the source types A and B directly, it works as expected:

Mapped type

We can create a utility type to rename a key:

type Rename<ObjectType, FromKey extends PropertyKey, ToKey extends PropertyKey> = {
    [Key in keyof ObjectType as Key extends FromKey ? ToKey : Key]: ObjectType[Key];
}

Like Omit, that will be distributed across the A | B union, giving us the result we want:

type After = Rename<Before, "name", "name2">;

const a: After = {
    name2: "A",
    A: 2,
};

const b: After = {
    name2: "B",
    B: 2,
};

Playground link

From the source types

But if you didn't really need Before, you could just define After directly from A and B using Omit as you've shown:

type A = {
    name: "A";
    A: number;
};

type B = {
    name: "B";
    B: number;
};

type Before = A | B;

type After =
    | (Omit<A, "name"> & { name2: A["name"] })
    | (Omit<B, "name"> & { name2: B["name"] });

const a: After = {
    name2: "A",
    A: 2,
};

const b: After = {
    name2: "B",
    B: 2,
};

Playground link

  • Related