ฉันจะกำหนดได้อย่างไรว่า Typescript generic T[K] เป็นประเภทตัวเลข?
ฉันมีฟังก์ชัน Typescript ง่าย ๆ แบบนี้:
function getProperty<T, K extends keyof T>(obj: T, key: K): number {
return obj[key]; // This line is not compiling.
// Typescript will yell: "Type 'T[K]' is not assignable to type 'number'."
}
การใช้งานของฉันดูเหมือนนี้:
const someObj = {
myValue: 123,
otherProperty: '321'
}
getProperty(someObj, 'myValue')
ฉันจะไม่รู้ว่าโครงสร้างของ someObj จะเป็นอย่างไร
คำถามของฉันคือ: ฉันสามารถระบุได้อย่างไรว่า T[K] เป็นประเภทตัวเลขแบบสแตติก?
คำตอบ #1
ถ้าวัตถุที่คุณกำลังทำงานด้วยมีการกำหนดชนิดมากพอที่จะทำให้ TypeScript รู้รูปร่างของมันแล้ว คุณสามารถทำแบบนี้ได้เลย [ลิงก์ playground ของ TypeScript ถ้าคุณอยากทดลองเล็กน้อย]
คุณเพียงแค่ต้องจำกัดว่า identifier key สามารถเป็นเพียงหนึ่งในสิ่งนั้นที่อ้างอิงคุณสมบัติประเภท number:
const someObj = {
myValue: 123,
otherProperty: '321'
};
getProperty(someObj, 'myValue'); // works
getProperty(someObj, 'otherProperty'); // wails
function getProperty<T, K extends NumericProps<T>>(obj: T, key: K): number {
return obj[key];
}
type NumericProps<T> = {
[K in keyof T]: T[K] extends number ? K : never
}[keyof T];
คำตอบ #2
ฉันจะไม่รู้ว่าโครงสร้างของ
someObjจะเป็นอย่างไร
แล้ว TypeScript ก็ไม่สามารถช่วยคุณได้จริง ๆ ในเรื่องนี้ การตรวจสอบชนิดของ TypeScript จะทำที่ เวลาแปลโค้ด หากโครงสร้างของ someObj จะทราบได้ก็ต่อเมื่อ เวลารันไทม์ TypeScript จึงไม่สามารถทำให้การเข้าถึงโครงสร้างนั้นปลอดภัยตามชนิดได้ คุณจำเป็นต้องรู้ว่าคีย์ของคุณสมบัติและค่าที่เป็นไปได้ของคุณสมบัติเหล่านั้นคืออะไร ณ เวลาแปลโค้ด
ตัวอย่างเช่น: ในตัวอย่างของคุณ ชื่อสมบัติเป็นสตริงและค่าของสมบัติเป็นสตริงหรือจำนวน (แต่ไม่ใช่บูลีนหรืออ็อบเจ็กต์ เป็นต้น) คุณสามารถประกาศชนิดที่มีดัชนีตามสตริง (เนื่องจากชื่อสมบัติทั้งหมดสุดท้ายเป็นสตริงหรือสัญลักษณ์ ในกรณีนี้คือสตริง) ที่ค่าของสมบัติเป็นตัวเลขหรือสตริง:
declare type SomeObjType = {
[key: string]: number | string
};
และจากนั้น getProperty คือ:
function getProperty<T extends SomeObjType>(obj: T, key: string): number | string {
return obj[key];
}
และคุณสามารถใช้มันแบบนี้ (ในกรณีนี้ ผมใช้ JSON.parse เพื่อจำลองการรับข้อมูลนี้จากภายนอกขอบเขตของโปรแกรม):
const someObj: SomeObjType = JSON.parse(`{
"myValue": 123,
"otherProperty": "321"
}`);
console.log(getProperty(someObj, 'myValue'));
console.log(getProperty(someObj, 'otherProperty'));
บนสนามเด็กเล่น
แต่นั่นก็ไม่ได้ช่วยอะไรมากนัก และยังปิดกั้นความเป็นไปได้ที่ค่าของทรัพย์สินจะเป็นสิ่งอื่นนอกจากตัวเลขหรือสตริง
คุณอาจจำเป็นต้องใช้ object:
function getProperty(obj: object, key: string) {
return obj[key];
}
const someObj = JSON.parse(`{
"myValue": 123,
"otherProperty": "321"
}`);
console.log(getProperty(someObj, 'myValue'));
console.log(getProperty(someObj, 'otherProperty'));
บนสนามเด็กเล่น
