รับคีย์ของอินเทอร์เฟซ typescript เป็นอาร์เรย์ของสตริง


124

ฉันมีตารางมากมายในLovefieldและอินเทอร์เฟซตามลำดับสำหรับคอลัมน์ที่พวกเขามี

ตัวอย่าง:

export interface IMyTable {
  id: number;
  title: string;
  createdAt: Date;
  isDeleted: boolean;
}

ฉันต้องการตั้งชื่อคุณสมบัติของอินเทอร์เฟซนี้ในอาร์เรย์ดังนี้:

const IMyTable = ["id", "title", "createdAt", "isDeleted"];

ฉันไม่สามารถสร้างออบเจ็กต์ / อาร์เรย์ตามอินเทอร์เฟซIMyTableโดยตรงซึ่งควรทำเคล็ดลับเพราะฉันได้รับชื่ออินเทอร์เฟซของตารางแบบไดนามิก ดังนั้นฉันต้องวนซ้ำคุณสมบัติเหล่านี้ในอินเทอร์เฟซและดึงอาร์เรย์ออกมา

ฉันจะบรรลุผลลัพธ์นี้ได้อย่างไร?

คำตอบ:


58

สำหรับTypeScript 2.3 (หรือฉันควรจะพูดว่า2.4เนื่องจากใน2.3คุณสมบัตินี้มีข้อผิดพลาดซึ่งได้รับการแก้ไขในtypescript@2.4-dev ) คุณสามารถสร้างหม้อแปลงที่กำหนดเองเพื่อให้บรรลุสิ่งที่คุณต้องการทำ

อันที่จริงฉันได้สร้างหม้อแปลงแบบกำหนดเองแล้วซึ่งเปิดใช้งานสิ่งต่อไปนี้

https://github.com/kimamula/ts-transformer-keys

import { keys } from 'ts-transformer-keys';

interface Props {
  id: string;
  name: string;
  age: number;
}
const keysOfProps = keys<Props>();

console.log(keysOfProps); // ['id', 'name', 'age']

น่าเสียดายที่หม้อแปลงไฟฟ้าแบบกำหนดเองในปัจจุบันใช้งานไม่ง่ายนัก คุณต้องใช้กับAPI การแปลงTypeScriptแทนการรันคำสั่ง tsc มีปัญหาในการร้องขอการสนับสนุนปลั๊กอินสำหรับหม้อแปลงที่กำหนดเอง


ขอบคุณสำหรับการตอบกลับของคุณฉันได้เห็นและติดตั้งหม้อแปลงที่กำหนดเองนี้แล้วเมื่อวานนี้ แต่เนื่องจากสิ่งนี้ใช้ typescript 2.4 สิ่งนี้จึงไม่มีประโยชน์สำหรับฉัน ณ ตอนนี้
Tushar Shukla

18
สวัสดีไลบรารีนี้ตอบสนองความต้องการของฉันด้วยเช่นกันอย่างไรก็ตามฉันได้รับts_transformer_keys_1.keys is not a functionเมื่อฉันทำตามขั้นตอนที่แน่นอนในเอกสาร มีวิธีแก้ปัญหานี้หรือไม่
Hasitha Shan

เรียบร้อย! คุณคิดว่าสามารถขยายเพื่อรับพารามิเตอร์ประเภทไดนามิก (หมายเหตุ 2 ใน readme) ได้หรือไม่
kenshin

@HasithaShan ดูเอกสารอย่างใกล้ชิด - คุณต้องใช้ API คอมไพเลอร์ TypeScript เพื่อให้แพคเกจทำงาน
Yaroslav Bai

4
น่าเสียดายที่แพ็คเกจเสียไม่ว่าฉันจะทำอะไรก็ตามts_transformer_keys_1.keys is not a function
fr1sk

20

สิ่งต่อไปนี้ต้องการให้คุณแสดงรายการคีย์ด้วยตัวคุณเอง แต่อย่างน้อย TypeScript จะบังคับใช้IUserProfileและIUserProfileKeysมีคีย์เดียวกันทุกRequired<T>ประการ ( ถูกเพิ่มใน TypeScript 2.8 ):

export interface IUserProfile  {
  id: string;
  name: string;
};
type KeysEnum<T> = { [P in keyof Required<T>]: true };
const IUserProfileKeys: KeysEnum<IUserProfile> = {
  id: true,
  name: true,
};

เคล็ดลับสวย ๆ ตอนนี้มันเป็นเรื่องง่ายที่จะบังคับใช้การดำเนินการคีย์ทั้งหมดIUserProfileและจะเป็นเรื่องง่ายที่จะดึงพวกเขาจาก IUserProfileKeysconst นี่คือสิ่งที่ฉันกำลังมองหา ไม่จำเป็นต้องแปลงอินเทอร์เฟซทั้งหมดของฉันเป็นคลาสตอนนี้
Anddo

17

ฉันมีปัญหาคล้าย ๆ กันว่าฉันมีรายการคุณสมบัติมากมายที่ฉันต้องการมีทั้งอินเทอร์เฟซและอ็อบเจ็กต์

หมายเหตุ: ฉันไม่ต้องการเขียนคุณสมบัติ (พิมพ์ด้วยแป้นพิมพ์) สองครั้ง! เพียงแค่แห้ง


สิ่งหนึ่งที่ควรทราบก็คืออินเทอร์เฟซเป็นประเภทที่บังคับใช้ในเวลาคอมไพล์ในขณะที่อ็อบเจ็กต์ส่วนใหญ่เป็นรันไทม์ ( ที่มา )

ในฐานะที่เป็น @derek กล่าวถึงในคำตอบอื่น , ตัวหารร่วมของอินเตอร์เฟซและวัตถุสามารถระดับที่ทำหน้าที่ทั้งจำทั้งประเภทและมูลค่า

ดังนั้น TL; DR โค้ดต่อไปนี้ควรตอบสนองความต้องการ:

class MyTableClass {
    // list the propeties here, ONLY WRITTEN ONCE
    id = "";
    title = "";
    isDeleted = false;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// This is the pure interface version, to be used/exported
interface IMyTable extends MyTableClass { };

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// Props type as an array, to be exported
type MyTablePropsArray = Array<keyof IMyTable>;

// Props array itself!
const propsArray: MyTablePropsArray =
    Object.keys(new MyTableClass()) as MyTablePropsArray;

console.log(propsArray); // prints out  ["id", "title", "isDeleted"]


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// Example of creating a pure instance as an object
const tableInstance: MyTableClass = { // works properly!
    id: "3",
    title: "hi",
    isDeleted: false,
};

( นี่คือโค้ดด้านบนใน typescript Playground เพื่อเล่นเพิ่มเติม)

ปล. หากคุณไม่ต้องการกำหนดค่าเริ่มต้นให้กับคุณสมบัติในคลาสและอยู่กับประเภทคุณสามารถใช้เคล็ดลับตัวสร้าง:

class MyTableClass {
    // list the propeties here, ONLY WRITTEN ONCE
    constructor(
        readonly id?: string,
        readonly title?: string,
        readonly isDeleted?: boolean,
    ) {}
}

console.log(Object.keys(new MyTableClass()));  // prints out  ["id", "title", "isDeleted"] 

เคล็ดลับในตัวสร้าง typescript สนามเด็กเล่น


propsArrayสามารถเข้าถึงได้เฉพาะเมื่อคุณเริ่มต้นปุ่มแม้ว่า
denkquer

ฉันไม่เข้าใจว่าคุณ "initialized" @denkquer หมายถึงอะไร ในตัวอย่างแรกpropsArrayมีให้ก่อนtableInstanceif นั่นคือสิ่งที่คุณหมายถึงให้ชัดเจนก่อนเริ่มต้นอินสแตนซ์ อย่างไรก็ตามหากคุณอ้างถึงค่าปลอมที่กำหนดไว้ค่าMyTableClassเหล่านี้จะบ่งบอกถึง "ประเภท" ของคุณสมบัติในไม่ช้า หากคุณไม่ต้องการคุณสามารถใช้เคล็ดลับตัวสร้างในตัวอย่าง PS
Aidin

1
ในความเข้าใจของฉันค่าจะเริ่มต้นเมื่อมีค่าใด ๆ "เคล็ดลับตัวสร้าง" ของคุณทำให้เข้าใจผิดเพราะคุณไม่สามารถแทนที่MyTableClassด้วยอันหลังได้และคาดว่าจะได้รับคีย์ในpropsArrayvars และประเภทที่ไม่ได้กำหนดค่าเริ่มต้นจะถูกปล้นเมื่อรันไทม์ คุณต้องจัดหาค่าเริ่มต้นบางประเภทให้เสมอ ฉันพบว่าการเริ่มต้นด้วยundefinedเป็นแนวทางที่ดีที่สุด
denkquer

1
@Aidin ขอบคุณสำหรับการแก้ปัญหาของคุณ ฉันยังสงสัยว่าฉันสามารถหลีกเลี่ยงการเริ่มต้นของพารามิเตอร์ได้หรือไม่ ถ้าฉันใช้เคล็ดลับตัวสร้างฉันไม่สามารถสร้างอินเทอร์เฟซที่ขยาย MyTableClass ได้อีกต่อไป .. เคล็ดลับตัวสร้างของคุณในลิงค์สนามเด็กเล่น typescript ว่างเปล่า
Flion

1
@ Flion ขอบคุณที่สังเกตเห็น ฉันเพิ่งอัปเดตลิงก์สนามเด็กเล่นสำหรับเคล็ดลับตัวสร้าง ดูว่าตอนนี้ใช้งานได้หรือไม่
Aidin

15

อาจจะสายเกินไป แต่ใน TypeScript เวอร์ชัน 2.1 คุณสามารถใช้ได้key ofดังนี้:

interface Person {
    name: string;
    age: number;
    location: string;
}

type K1 = keyof Person; // "name" | "age" | "location"
type K2 = keyof Person[];  // "length" | "push" | "pop" | "concat" | ...
type K3 = keyof { [x: string]: Person };  // string

ที่มา: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html#keyof-and-lookup-types


ขอบคุณสำหรับคำตอบ แต่ไม่แน่ใจว่าจะช่วยให้ใครบางคนใช้ประเภทที่สร้างแบบคงที่จากอินเทอร์เฟซได้หรือไม่ IMHO เราสามารถใช้อินเทอร์เฟซ / ประเภทแทนกันได้ในเกือบทุกกรณี นอกจากนี้จะต้องมีการสร้างประเภทด้วยตนเองสำหรับอินเทอร์เฟซหลาย ๆ อย่างไรก็ตามวิธีแก้ปัญหาจะดูดีหากมีคนต้องการเพียงแค่แยกประเภทออกจากอินเทอร์เฟซ
Tushar Shukla

11

ตัวแปรที่ปลอดภัย

การสร้างอาร์เรย์หรือทูเปิลของคีย์จากอินเทอร์เฟซที่มีการตรวจสอบเวลาคอมไพล์ความปลอดภัยต้องใช้ความคิดสร้างสรรค์เล็กน้อย ประเภทจะถูกลบที่ใช้เวลาและประเภทวัตถุ (เรียงลำดับชื่อ) ไม่สามารถแปลงเป็นประเภท tuple (สั่งไม่มีชื่อ) โดยไม่ต้อง resorting เทคนิคที่ไม่ได้รับการสนับสนุน

เปรียบเทียบกับคำตอบอื่น ๆ

ที่นำเสนอที่นี่ทุกสายพันธุ์พิจารณา / เรียกรวบรวมข้อผิดพลาดในกรณีที่ซ้ำกันหรือขาดหายไปรายการ tuple IMyTableกำหนดชนิดของวัตถุอ้างอิงเช่น ตัวอย่างเช่นการประกาศประเภทอาร์เรย์ที่(keyof IMyTable)[]ไม่สามารถตรวจจับข้อผิดพลาดเหล่านี้

นอกจากนี้พวกเขาไม่ต้องการไลบรารีเฉพาะ (ใช้ตัวแปรสุดท้ายts-morphซึ่งฉันจะพิจารณาว่าเป็น Wrapper คอมไพเลอร์ทั่วไป) ปล่อยประเภททูเพิลซึ่งตรงข้ามกับอ็อบเจ็กต์ (เฉพาะโซลูชันแรกเท่านั้นที่สร้างอาร์เรย์) หรือประเภทอาร์เรย์แบบกว้าง (เปรียบเทียบกับเหล่านี้ คำตอบ ) และสุดท้ายการเรียนไม่จำเป็นต้อง

ตัวแปร 1: อาร์เรย์ที่พิมพ์ง่าย

// Record type ensures, we have no double or missing keys, values can be neglected
function createKeys(keyRecord: Record<keyof IMyTable, any>): (keyof IMyTable)[] {
  return Object.keys(keyRecord) as any
}

const keys = createKeys({ isDeleted: 1, createdAt: 1, title: 1, id: 1 })
// const keys: ("id" | "title" | "createdAt" | "isDeleted")[]

++-คู่มือที่ง่ายที่สุดพร้อม-อาร์เรย์การเติมข้อความอัตโนมัติไม่มีทูเพิล

สนามเด็กเล่น

ถ้าคุณทำไม่ได้เช่นการสร้างบันทึกดูที่ทางเลือกนี้ด้วยSetและประเภทการยืนยัน


ตัวแปร 2: Tuple พร้อมฟังก์ชันตัวช่วย

function createKeys<T extends readonly (keyof IMyTable)[] | [keyof IMyTable]>(
    t: T & CheckMissing<T, IMyTable> & CheckDuplicate<T>): T {
    return t
}

++-คู่มือtuple พร้อมการเติมอัตโนมัติ+-ขั้นสูงและประเภทที่ซับซ้อนมากขึ้น

สนามเด็กเล่น

คำอธิบาย

createKeysทำการตรวจสอบเวลาคอมไพล์โดยการรวมประเภทพารามิเตอร์ของฟังก์ชันเข้ากับประเภทการยืนยันเพิ่มเติมซึ่งทำให้เกิดข้อผิดพลาดสำหรับอินพุตที่ไม่เหมาะสม (keyof IMyTable)[] | [keyof IMyTable]เป็นวิธี"มนต์ดำ"เพื่อบังคับให้อนุมานทูเพิลแทนที่จะเป็นอาร์เรย์จากด้านแคลลี หรือคุณสามารถใช้การยืนยัน const /as constจากฝั่งผู้โทร

CheckMissingตรวจสอบหากTพลาดคีย์จากU:

type CheckMissing<T extends readonly any[], U extends Record<string, any>> = {
    [K in keyof U]: K extends T[number] ? never : K
}[keyof U] extends never ? T : T & "Error: missing keys"

type T1 = CheckMissing<["p1"], {p1:any, p2:any}> //["p1"] & "Error: missing keys"
type T2 = CheckMissing<["p1", "p2"], { p1: any, p2: any }> // ["p1", "p2"]

หมายเหตุ: T & "Error: missing keys"เป็นเพียงข้อผิดพลาด IDE ที่ดี neverนอกจากนี้คุณยังสามารถเขียน CheckDuplicatesตรวจสอบรายการทูเปิลสองครั้ง:

type CheckDuplicate<T extends readonly any[]> = {
    [P1 in keyof T]: "_flag_" extends
    { [P2 in keyof T]: P2 extends P1 ? never :
        T[P2] extends T[P1] ? "_flag_" : never }[keyof T] ?
    [T[P1], "Error: duplicate"] : T[P1]
}

type T3 = CheckDuplicate<[1, 2, 3]> // [1, 2, 3]
type T4 = CheckDuplicate<[1, 2, 1]> 
// [[1, "Error: duplicate"], 2, [1, "Error: duplicate"]]

หมายเหตุ: ข้อมูลเพิ่มเติมเกี่ยวกับการตรวจสอบไอเท็มที่ไม่ซ้ำกันใน tuples อยู่ในโพสต์นี้ ด้วยTS 4.1เราสามารถตั้งชื่อคีย์ที่หายไปในสตริงข้อผิดพลาดได้ - ลองดูที่Playgroundนี้


ตัวแปร 3: ชนิดเรียกซ้ำ

ด้วยเวอร์ชัน 4.1 TypeScript สนับสนุนประเภทการเรียกซ้ำตามเงื่อนไขอย่างเป็นทางการซึ่งสามารถใช้ได้ที่นี่เช่นกัน แม้ว่าการคำนวณประเภทจะมีราคาแพงเนื่องจากความซับซ้อนร่วมกัน - ประสิทธิภาพลดลงอย่างมากสำหรับรายการมากกว่า 5-6 รายการ ฉันแสดงรายการทางเลือกนี้เพื่อความสมบูรณ์ ( Playground ):

type Prepend<T, U extends any[]> = [T, ...U] // TS 4.0 variadic tuples

type Keys<T extends Record<string, any>> = Keys_<T, []>
type Keys_<T extends Record<string, any>, U extends PropertyKey[]> =
  {
    [P in keyof T]: {} extends Omit<T, P> ? [P] : Prepend<P, Keys_<Omit<T, P>, U>>
  }[keyof T]

const t1: Keys<IMyTable> = ["createdAt", "isDeleted", "id", "title"] // ✔

++-คู่มือtuple พร้อมการเติมอัตโนมัติ+ไม่มีตัวช่วย--ประสิทธิภาพของฟังก์ชัน


ตัวแปร 4: Code generator / TS compiler API

ts-morphถูกเลือกที่นี่เนื่องจากเป็นทางเลือกของ wrapper ที่ง่ายกว่าเล็กน้อยสำหรับTS คอมไพเลอร์ APIดั้งเดิม แน่นอนคุณยังสามารถใช้ API ของคอมไพเลอร์ได้โดยตรง ลองดูรหัสเครื่องกำเนิดไฟฟ้า:

// ./src/mybuildstep.ts
import {Project, VariableDeclarationKind, InterfaceDeclaration } from "ts-morph";

const project = new Project();
// source file with IMyTable interface
const sourceFile = project.addSourceFileAtPath("./src/IMyTable.ts"); 
// target file to write the keys string array to
const destFile = project.createSourceFile("./src/generated/IMyTable-keys.ts", "", {
  overwrite: true // overwrite if exists
}); 

function createKeys(node: InterfaceDeclaration) {
  const allKeys = node.getProperties().map(p => p.getName());
  destFile.addVariableStatement({
    declarationKind: VariableDeclarationKind.Const,
    declarations: [{
        name: "keys",
        initializer: writer =>
          writer.write(`${JSON.stringify(allKeys)} as const`)
    }]
  });
}

createKeys(sourceFile.getInterface("IMyTable")!);
destFile.saveSync(); // flush all changes and write to disk

หลังจากที่เรารวบรวมและเรียกใช้ไฟล์นี้tsc && node dist/mybuildstep.jsแล้วไฟล์ที่./src/generated/IMyTable-keys.tsมีเนื้อหาต่อไปนี้จะถูกสร้างขึ้น:

// ./src/generated/IMyTable-keys.ts
const keys = ["id","title","createdAt","isDeleted"] as const;

+โซลูชันที่สร้างขึ้นโดยอัตโนมัติ+สามารถปรับขนาดได้สำหรับคุณสมบัติหลายอย่าง+ไม่มีฟังก์ชันตัวช่วย+tuple -extra build-step -ต้องการความคุ้นเคยกับ compiler API


10

สิ่งนี้ควรใช้งานได้

var IMyTable: Array<keyof IMyTable> = ["id", "title", "createdAt", "isDeleted"];

หรือ

var IMyTable: (keyof IMyTable)[] = ["id", "title", "createdAt", "isDeleted"];

18
ไม่ใช่ว่าผิด แต่ที่ชัดเจนคุณแค่ "บังคับใช้ค่าของอาร์เรย์" ให้ถูกต้อง นักพัฒนายังคงต้องจดบันทึกสองครั้งด้วยตนเอง
Aidin

แม้ว่าสิ่งที่ไอดินพูดอาจจะเป็นความจริง แต่ในบางกรณีนี่คือสิ่งที่ฉันกำลังมองหาสำหรับกรณีของฉัน ขอขอบคุณ.
Daniel

4
วิธีนี้จะไม่ป้องกันคีย์ที่ซ้ำกันหรือคีย์หายไป ชอบvar IMyTable: Array<keyof IMyTable> = ["id", "createdAt", "id"];
ford04

สำหรับฉันมันเป็นสิ่งที่ฉันกำลังมองหาเพราะฉันต้องการที่จะยอมรับคีย์ แต่ไม่มีอะไรมากไปกว่าคีย์ที่กำหนดในอินเทอร์เฟซ ไม่ได้คาดหวังว่าสิ่งนี้จะเป็นค่าเริ่มต้นด้วยรหัสด้านบน ฉันเดาว่าเราคงต้องการวิธี TS ทั่วไปสำหรับสิ่งนั้น ขอบคุณไม่ว่าในกรณีใด ๆ สำหรับรหัสด้านบน!
nicoes

7

แทนที่จะกำหนดIMyTableเป็นอินเทอร์เฟซให้ลองกำหนดเป็นคลาส ใน typescript คุณสามารถใช้คลาสเช่นอินเทอร์เฟซ

ดังนั้นสำหรับตัวอย่างของคุณกำหนด / สร้างชั้นเรียนของคุณดังนี้:

export class IMyTable {
    constructor(
        public id = '',
        public title = '',
        public createdAt: Date = null,
        public isDeleted = false
    )
}

ใช้เป็นอินเทอร์เฟซ:

export class SomeTable implements IMyTable {
    ...
}

รับกุญแจ:

const keys = Object.keys(new IMyTable());

5

คุณจะต้องสร้างคลาสที่ใช้อินเทอร์เฟซของคุณสร้างอินสแตนซ์จากนั้นจึงใช้Object.keys(yourObject)เพื่อรับคุณสมบัติ

export class YourClass implements IMyTable {
    ...
}

แล้ว

let yourObject:YourClass = new YourClass();
Object.keys(yourObject).forEach((...) => { ... });

ไม่ได้ผลในกรณีของฉันฉันต้องแสดงรายการคุณสมบัติเหล่านั้นของอินเทอร์เฟซ แต่นั่นไม่ใช่สิ่งที่ฉันต้องการ? ชื่อของอินเทอร์เฟซมาแบบไดนามิกจากนั้นฉันต้องกำหนดคุณสมบัติของมัน
Tushar Shukla

สิ่งนี้ก่อให้เกิดข้อผิดพลาด (v2.8.3): Cannot extend an interface […]. Did you mean 'implements'?อย่างไรก็ตามการใช้implementsแทนต้องคัดลอกอินเทอร์เฟซด้วยตนเองซึ่งเป็นสิ่งที่ฉันไม่ต้องการ
jacob

@jacob ขอโทษมันควรจะเป็นimplementsและฉันได้อัปเดตคำตอบของฉันแล้ว ตามที่ @basarat ระบุไว้ว่าอินเทอร์เฟซไม่มีอยู่ที่รันไทม์ดังนั้นวิธีเดียวคือใช้เป็นคลาส
Dan Def

คุณหมายถึงแทนที่จะใช้อินเทอร์เฟซใช้คลาส? ขออภัยฉันไม่สามารถเนื่องจากอินเทอร์เฟซมาจากบุคคลที่สาม ( @types/react) ฉันคัดลอกด้วยตนเอง แต่นั่นแทบจะไม่สามารถพิสูจน์ได้ในอนาคต trying ฉันกำลังพยายามเชื่อมโยงวิธีการที่ไม่ใช่วงจรชีวิตแบบไดนามิก (ซึ่งถูกผูกไว้แล้ว) แต่ไม่ได้ประกาศใน React.Component (คลาส)
jacob

ไม่ฉันหมายถึงสร้างคลาสที่ใช้อินเทอร์เฟซบุคคลที่สามของคุณและรับคุณสมบัติของคลาสนั้นที่รันไทม์
Dan Def

4

ลาด. ไม่มีอินเทอร์เฟซที่รันไทม์

วิธีแก้ปัญหาชั่วคราว

สร้างตัวแปรประเภทและใช้Object.keysกับมัน🌹


1
คุณหมายถึงแบบนี้var abc: IMyTable = {}; Object.keys(abc).forEach((key) => {console.log(key)});
Tushar Shukla

4
ไม่เพราะวัตถุนั้นไม่มีกุญแจอยู่ อินเทอร์เฟซเป็นสิ่งที่ TypeScript ใช้ แต่ระเหยไปใน JavaScript ดังนั้นจึงไม่มีข้อมูลเหลือที่จะแจ้งให้ทราบถึง "การสะท้อน" หรือ "การตัดกัน" ใด ๆ JavaScript ทั้งหมดรู้ว่ามีตัวอักษรว่างเปล่า ความหวังเดียวของคุณคือการรอ (หรือร้องขอ ) TypeScript มีวิธีสร้างอาร์เรย์หรือวัตถุที่มีคีย์ทั้งหมดในอินเทอร์เฟซลงในซอร์สโค้ด หรืออย่างที่ Dan Def บอกถ้าคุณสามารถใช้คลาสได้คุณจะมีคีย์ที่กำหนดในรูปแบบของคุณสมบัติในทุกๆกรณี ..
Jesper

17
หากไม่ได้ผลเหตุใดจึงมีการโหวตให้คะแนนคำตอบนี้
dawez

2
เหตุผลในการโหวตลงคะแนน: ไม่มีการระบุว่าใช้ไม่ได้กับค่าที่เป็นโมฆะ
โหวตลดลงโมฆะ TamusJRoyce

2
ท้ายที่สุดแล้วไม่ใช่วิธีแก้ปัญหาที่ดีเพราะคุณต้องให้คุณค่า น่าจะดีกว่าแค่เก็บรายการกุญแจไว้
Daniel Thompson

0

นี่เป็นเรื่องยาก! ขอบคุณทุกคนสำหรับความช่วยเหลือของคุณ

ความต้องการของฉันคือรับคีย์ของอินเทอร์เฟซเป็นอาร์เรย์ของสตริงเพื่อลดความซับซ้อนของการเขียนสคริปต์ mocha / chai ไม่เกี่ยวกับการใช้งานในแอพ (ยัง) จึงไม่จำเป็นต้องสร้างไฟล์ ts ขอบคุณford04สำหรับความช่วยเหลือวิธีแก้ปัญหาของเขาข้างต้นช่วยได้มากและทำงานได้อย่างสมบูรณ์ไม่มีคอมไพเลอร์แฮ็ก นี่คือรหัสที่แก้ไข:

ตัวเลือกที่ 2: ตัวสร้างโค้ดตาม TS คอมไพเลอร์ API (ts-morph)

โมดูลโหนด

npm install --save-dev ts-morph

keys.ts

บันทึก : ถือว่าไฟล์ ts ทั้งหมดอยู่ในรูทของ. / src และไม่มีโฟลเดอร์ย่อยให้ปรับตาม

import {
  Project,
  VariableDeclarationKind,
  InterfaceDeclaration,
} from "ts-morph";

// initName is name of the interface file below the root, ./src is considered the root
const Keys = (intName: string): string[] => {
  const project = new Project();
  const sourceFile = project.addSourceFileAtPath(`./src/${intName}.ts`);
  const node = sourceFile.getInterface(intName)!;
  const allKeys = node.getProperties().map((p) => p.getName());

  return allKeys;
};

export default Keys;

การใช้งาน

import keys from "./keys";

const myKeys = keys("MyInterface") //ts file name without extension

console.log(myKeys)

-1

คุณไม่สามารถทำได้ ไม่มีอินเทอร์เฟซที่รันไทม์ (เช่น@basaratกล่าว)

ตอนนี้ฉันกำลังดำเนินการดังต่อไปนี้:

const IMyTable_id = 'id';
const IMyTable_title = 'title';
const IMyTable_createdAt = 'createdAt';
const IMyTable_isDeleted = 'isDeleted';

export const IMyTable_keys = [
  IMyTable_id,
  IMyTable_title,
  IMyTable_createdAt,
  IMyTable_isDeleted,
];

export interface IMyTable {
  [IMyTable_id]: number;
  [IMyTable_title]: string;
  [IMyTable_createdAt]: Date;
  [IMyTable_isDeleted]: boolean;
}

ลองนึกภาพว่ามีแบบจำลองมากมายและทำเพื่อทุกคน ... มันเป็นเวลาที่แพงมาก
William Cuervo

-7
// declarations.d.ts
export interface IMyTable {
      id: number;
      title: string;
      createdAt: Date;
      isDeleted: boolean
}
declare var Tes: IMyTable;
// call in annother page
console.log(Tes.id);

1
โค้ดนี้จะไม่ทำงานเนื่องจากไวยากรณ์ typescript ไม่พร้อมใช้งานในขณะทำงาน หากคุณตรวจสอบรหัสนี้ในสนามเด็กเล่น typescript คุณจะสังเกตเห็นว่าสิ่งเดียวที่รวบรวมไปยัง JavaScript คือconsole.log(Tes.id)ข้อผิดพลาดที่แน่นอนคือข้อผิดพลาด 'Uncaught ReferenceError: Tes ไม่ได้กำหนด'
Tushar Shukla
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.