typescript2.0 - Skillnader mellan gränssnitt i Typescript?


Jag har ett par gränssnitt:

interface ISubstitution {
   id: number;
   name: string;
   date: string;
   subject: number;
   new: string;
   group: number;
   form: boolean;
}

interface ISubstitutionHot {
  new: string;
  group: number;
  form: boolean;
}

Motsvarande är ett objekt av gränssnittstyp:

public a: any;
a = <ISubstitution> {
       id: 1,
       name:"O",
       date: "2018-01-1",
       subject: "M",
       new: "A", 
       group: 1,
       form: true
}

Observera att ISubstitutionHot utökar ISubstitution.

Så, sammanfattningsvis har jag fyllt objekt a.

Hur man tar skillnaden mellan objekt/gränssnitt som:

let c = <a>ISubstitution / <b>ISubstitutionHot;

För att bara hämta fält från objektet a som finns i gränssnittet ISubstitutionHot? Det borde returnera mig:

c = {
new: "A", 
group: 1,
form: true
}

Är det möjligt i TypeScript?

Svar #1

Typer och gränssnitt i TypeScript existerar endast vid kompilerings-/design-tid, och tas bort när koden kompileras till JavaScript. Det betyder att det enda sättet att få något att hända vid körning är om du placerar den information du behöver i ett värde och inte bara i en typ. Här är ett sätt att gå vidare:

Först, definiera hotKeys, en array av strängarna "new", "group" och "form". Funktionen keyArray() är bara en hjälpfunktion som tillåter TypeScript att härleda de literala typerna istället för bara string[]:

const keyArray = <K extends string>(...keys: K[]) => keys;
const hotKeys = keyArray('new', 'group', 'form');
type HotKeys = typeof hotKeys[number];

Om du inspekterar det, är hotKeys av typen ('new' | 'group' | 'form')[], och därför är HotKeys 'new' | 'group' | 'form'.

Nu kommer vi att definiera pick()-funktionen, som tar ett objekt och en array av nycklar från det objektet och returnerar ett annat objekt med endast de egenskaper som motsvarar de nycklarna. Så här:

function pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {
  const ret = {} as Pick<T, K>; // empty to start
  keys.forEach(k => ret[k] = obj[k]); // copy some properties
  return ret; 
}

Detta är en generisk funktion som använder den inbyggda Pick-mappade typen.

Om du vill kan du antingen definiera ISubstitutionHot som ett gränssnitt på det sätt du har gjort, eller så kan du definiera det i termer av ISubstitution och HotKeys så här:

type ISubstitutionHot = Pick<ISubstitution, HotKeys>; 
// { new: string; group: number; form: boolean; }

Slutligen, låt oss skriva funktionen som konverterar en ISubstitution till en ISubtitutionHot:

function iSubstitutionHot(iSub: ISubstitution): ISubstitutionHot {
  return pick(iSub, hotKeys);
}

Det faktum att ovanstående funktion typkontrolleras utan fel är en indikation på att vi är på rätt spår.

Okej, låt oss prova det:

const a: ISubstitution = {
  id: 1,
  name: "O",
  date: "2018-01-1",
  subject: 1, // "M" <-- number!
  new: "A",
  group: 1,
  form: true
}

let c = iSubstitutionHot(a);
console.log(c); // { new: "A", group: 1, form: true }

Det fungerar! Du kan se koden i aktion här. Hoppas det hjälper. Lycka till.