Redenumește cheia tipului de obiect TypeScript


Am asta:

type Two = {
  one: number,
  two: string,
  three: boolean
}

Vreau să creeze un tip care să arate astfel:

type RenamedTwo = {
  one: number,
  two: string,
  four: boolean // difference
}

Am încercat să-l creez în felul acesta:

type Rename<T, K extends keyof T, N> = Pick<T, Exclude<keyof T, K>> & { [N]: T[K] }

Într-o încercare de a folosi această cale:

type Renamed = Rename<Two, 'three', 'four'>

Dar TSlint marchează [N] ca eroare și oferă acest mesaj de eroare:

[ts] Un nume de proprietate calculat într-un literal de tip trebuie să se refere la o expresie a cărei tip este un tip literal sau un tip 'symbol' unic. [ts] 'N' se referă doar la un tip, dar aici este folosit ca valoare.

Răspuns #1

Trebuie să folosești un tip mapat și pentru proprietatea redenumită:

type Two = {
    one: number,
    two: string,
    three: boolean
}


type Rename<T, K extends keyof T, N extends string> = Pick<T, Exclude<keyof T, K>> & { [P in N]: T[K] }

type Renamed = Rename<Two, 'three', 'four'>

Rețineți că acest lucru nu va funcționa așa cum vă așteptați dacă furnizați mai multe proprietăți:

type Renamed = Rename<Two, 'two'  |'three' , 'four' | 'five'> // will be Pick<Two, "one"> & {
//    four: string | boolean;
//    five: string | boolean;
// }

Răspunsul #2

În versiunea actuală de TypeScript 4.6.2, există o gramatică de remapare pe care o puteți utiliza. Aceasta poate fi implementată mult mai ușor.

PlayGround

type RenameByT<T, U> = {
  [K in keyof U as K extends keyof T
    ? T[K] extends string
      ? T[K]
      : never
    : K]: K extends keyof U ? U[K] : never;
};

type Two = { one: number; two: string; three: boolean };

// returnType = { one: number; two: string, four: boolean };
type renameOne = RenameByT<{three: 'four', five: 'nouse'}, Two>;

// returnType = { x: number, y: string, z: boolean; }
type renameAll = RenameByT<{one: 'x', two: 'y', three: 'z'}, Two>;

Tipul RenameByT poate separa în mai multe părți. Explicația este pentru exemplul renameOne

  1. K in keyof U înseamnă toate cheile din U. De exemplu, este one | two | three
  2. Clauza as poate fi folosită din ts4.1. Dar nu o pot folosi în 4.4.4, dar pot folosi în 4.6.2. Aceasta se folosește pentru a redenumi Key K prin tipul condiției
  3. K extinde keyof T. keyof T înseamnă three | five.
  4. T[K] extends string înseamnă că T[K] este string. T['three'] este string, așa că returnează four, T['five'] returnează nouse;
  5. tipul de returnare K extinde keyof U, astfel încât T['three'] satisface astfel returnează { four: U['three'] } înseamnă { four: boolean}
  6. alte taste se întorc la origine

referință:

https://github.com/microsoft/TypeScript/issues/40833 https://www.typescriptlang.org/docs/handbook/2/mapped-types.html