TypeScript ãžã§ããªãã¯ãš keyof ã§åã®å®å šæ§ãšåå©çšæ§ãé«ãã
TypeScriptã§äœæ¥ããŠãããšãæ§ã
ãªåã«å¯Ÿå¿ã§ããåå©çšå¯èœãªã³ãŒããæžããããªããšãããããŸãããŸãã«ãã®ãããªãšãã«ãžã§ããªãã¯ïŒGenericsïŒãå¿
èŠã§ãããããŠãkeyof æŒç®åãšçµã¿åãããŠäœ¿ãããšã§ãªããžã§ã¯ãã®ããããã£ãå®å
šã«æ±ãããšãã§ããŸããæ¬çš¿ã§ã¯ TypeScript ã®ãžã§ããªãã¯ãš keyof ã䜵çšããæ¹æ³ããå®çšçãªäŸãšãšãã«èŠãŠãããŸããããåºæ¬æŠå¿µããå®åã§å³é©çšã§ãããã¿ãŒã³ãŸã§ã段éçã«çè§£ã§ããããæ§æããŸããã
TypeScript ãžã§ããªãã¯ã®åºç€
ãžã§ããªãã¯ã¯åå©çšå¯èœãªã³ã³ããŒãã³ããäœãããã®éèŠãªéå ·ã§ãããæ§ã ãªåã«å¯Ÿå¿ãã€ã€åã®å®å šæ§ã確ä¿ããŸããäžã€ã®åã«éå®ãããããŸããŸãªåã«å¯Ÿå¿ã§ããã³ã³ããŒãã³ããäœãããšãã§ããŸããæãåºæ¬çãªäŸãidentity 颿°ãèŠãŠã¿ãŸãããã
function identity<T>(arg: T): T {
return arg;
}
ããã§ <T> ã¯å倿°ã§ãã颿°ãåŒã³åºãéã«æž¡ãããåããã£ããã£ããå
¥åãšåºåã®åãäžèŽãããŸããå倿°ã®ååã¯èªç±ã«å®ããããŸãããæ
£ç¿çã« TïŒType ã®ç¥ïŒã䜿ãããšãå€ãã§ãã
ãžã§ããªãã¯é¢æ°ã®åŒã³åºãæ¹
ãžã§ããªãã¯ã¯æç€ºçãªååŒæ°ãŸãã¯åæšè«ã§åŒã³åºããŸãããå¯èœã§ããã°åæšè«ãæšå¥šããŸãããžã§ããªãã¯é¢æ°ã¯æ¬¡ã®2ã€ã®æ¹æ³ã§åŒã³åºããŸãã
æç€ºçã«ååŒæ°ãæž¡ãå ŽåïŒ
let output = identity<string>("myString");
åæšè«ã掻çšããå ŽåïŒ
let output = identity("myString");
åŸè ã®æ¹æ³ã®ã»ããç°¡æœã§å¯èªæ§ãé«ããTypeScript ãèªåã§åãæšè«ã§ãããªããã¡ãã®æ¹åŒãæšå¥šããŸãã
å倿°ãããããæè»æ§
ãžã§ããªãã¯ã¯æ§ã ãªåãå®å šã«åãå ¥ããäžäžèŽãªåã®çµã¿åããã¯ã³ã³ãã€ã«æã«ãããã¯ããŸãã
function toArray<T>(a: T, b: T) {
return [a, b];
}
toArray<string>("hello", "world"); // string[] å
toArray<number>(1, 2); // number[] å
ããç°ãªãåã®åŒæ°ãæž¡ããšãã³ã³ãã€ã«æã«ãšã©ãŒãçºçããŸãïŒ
toArray<string>("hello", 1); // åãšã©ãŒïŒ
keyof æŒç®åã§ãžã§ããªãã¯ã«å¶çŽãå ãã
keyof ã¯ãªããžã§ã¯ãåã®ããŒã®ãŠããªã³ãæäŸãããžã§ããªãã¯å¶çŽãšçµã¿åãããããšã§ããããã£ã¢ã¯ã»ã¹ãåå®å
šã«ããŸããkeyof æŒç®åã¯ãªããžã§ã¯ãåã®ããŒããªãã©ã«åã®ãŠããªã³ãšããŠåãåºããŸããããããžã§ããªãã¯ãšäžç·ã«äœ¿ãããšã§åŒ·åãªåå¶çŽãäœãããšãã§ããŸãã
keyof ã®åºæ¬åäœ
interface Person {
name: string;
age: number;
}
type PersonKeys = keyof Person; // "name" | "age"
ãžã§ããªãã¯å¶çŽã§åã®å®å šæ§ã確ä¿ãã
Key extends keyof Type å¶çŽãéããŠååšããªãããããã£ã®ã¢ã¯ã»ã¹ãã³ã³ãã€ã«æ®µéã§ãããã¯ã§ããŸãã
function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) {
return obj[key];
}
const person = {
name: "Anna",
age: 30
};
getProperty(person, "name"); // â
æ£åžžåäœ
getProperty(person, "email"); // â åãšã©ãŒïŒ
éèŠãªãã³ã
ãžã§ããªãã¯å¶çŽã¯ã䜿çšãèš±å¯ããããŒã®éåããåãšããŠåŒ·å¶ããŸããã€ãŸããååšããªãããŒã¯ãããã颿°ã®åŒæ°ãšããŠèš±å¯ãããŸããã
ããããã£èšå®é¢æ°ãå®è£ ãã
T[K] ã®ã€ã³ããã¯ã¹ã¢ã¯ã»ã¹åã䜿ãã°ãå€ã®åãŸã§æ£ç¢ºã«å¶çŽã§ããŸãã
function setProperty<T, K extends keyof T>(obj: T, key: K, value: T[K]): void {
obj[key] = value;
}
const user = {
name: "John",
age: 25
};
setProperty(user, "name", "Jane"); // â
æ£åžž
setProperty(user, "name", 30); // â åãšã©ãŒïŒ (stringåã§ãªããã°ãªããªã)
setProperty(user, "email", "test@test.com"); // â åãšã©ãŒïŒ (ååšããªãããããã£)
ãžã§ããªãã¯ã€ã³ã¿ãŒãã§ãŒã¹ãšã¯ã©ã¹
颿°ã ãã§ãªãã€ã³ã¿ãŒãã§ãŒã¹ãšã¯ã©ã¹ã«ããžã§ããªãã¯ãé©çšããŠãæè»ãª API ãèšèšã§ããŸãã
ãžã§ããªãã¯ã€ã³ã¿ãŒãã§ãŒã¹
interface GenericIdentityFn<Type> {
(arg: Type): Type;
}
function identity<Type>(arg: Type): Type {
return arg;
}
let myIdentity: GenericIdentityFn<number> = identity;
ãžã§ããªãã¯ã¯ã©ã¹
class GenericNumber<NumType> {
zeroValue: NumType;
add: (x: NumType, y: NumType) => NumType;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) {
return x + y;
};
å®åäŸïŒ
class User<P> {
constructor(public payload: P) {
this.payload = payload;
}
getPayload() {
return this.payload;
}
}
const user1 = new User<{ name: string; age: number }>({
name: "Kim",
age: 28
});
const user2 = new User<string[]>(["admin", "user"]);
ãžã§ããªãã¯ã®å¶éäºé
TypeScript ã§ã¯ãžã§ããªã㯠enum ãš namespace ã¯äœæã§ããŸããããã㯠TypeScript ã®èšèšäžã®å¶éã§ãã
ããã©ã«ãåãã©ã¡ãŒã¿ãŒ
ãžã§ããªãã¯ã«ããã©ã«ãã®åãæå®ãããšãAPI ã®äœ¿ãããããåäžããäžè¬çãªã±ãŒã¹ãç°¡æœã«åŠçã§ããŸãã
function createHTMLElement<T extends HTMLElement = HTMLDivElement>(
element?: T
): T {
return element || (document.createElement('div') as T);
}
// ååŒæ°ãæç€ºããªããã° HTMLDivElement ã䜿çšãããŸã
const div = createHTMLElement();
// æç€ºçã«å¥ã®åãæå®ããããšãå¯èœã§ã
const button = createHTMLElement<HTMLButtonElement>(
document.createElement('button')
);
å®è·µäŸïŒåå®å šãªããŒã¿ã¢ã¯ã»ã¹ãã¿ãŒã³
API ã¬ã¹ãã³ã¹ããç¹å®ã®ããããã£ãå®å šã«åãåºããŠãŒãã£ã«ãäœãã°ãã©ã³ã¿ã€ã ã®ãšã©ãŒãã³ã³ãã€ã«ã¿ã€ã ã«é²ããŸãã
interface ApiResponse {
data: {
user: {
id: number;
name: string;
email: string;
};
posts: Array<{
id: number;
title: string;
}>;
};
meta: {
timestamp: number;
version: string;
};
}
function extractData<T, K extends keyof T>(response: T, key: K): T[K] {
return response[key];
}
const response: ApiResponse = {
data: {
user: { id: 1, name: "Lee", email: "lee@example.com" },
posts: [{ id: 1, title: "First Post" }]
},
meta: {
timestamp: Date.now(),
version: "1.0"
}
};
const data = extractData(response, "data"); // data ã®åãèªåã§æšè«ããã
const meta = extractData(response, "meta"); // meta ã®åãæ£ç¢ºã«æšè«ããã
ãã¹ããããããããã£ã«ã¢ã¯ã»ã¹ãã
ãã¹ãããããŒã段éçã«å¶çŽããã°ãæ·±ããã¹ã®ã¢ã¯ã»ã¹ãå®å šã«ã§ããŸãã
function getNestedProperty<
T,
K1 extends keyof T,
K2 extends keyof T[K1]
>(obj: T, key1: K1, key2: K2): T[K1][K2] {
return obj[key1][key2];
}
const userName = getNestedProperty(response, "data", "user"); // user ãªããžã§ã¯ãã®å
ãŠããªã³åãšãžã§ããªãã¯å¶çŽ
extends ã§ãŠããªã³ãæå®ããã°ãèš±å¯ããåãæ£ç¢ºã«éå®ã§ããŸãã
function hello<T extends string | number>(msg: T): T {
return msg;
}
hello(3); // â
number å
hello("hi"); // â
string å
hello([3, 5]); // â åãšã©ãŒïŒ (é
åã¯èš±å¯ãããªã)
keyof ãš typeof ã䜵çšãã
宿°ãªããžã§ã¯ãããå€ã®ãŠããªã³åãæœåºããå®åãã¿ãŒã³ã¯ãkeyof ãš typeof ã®çµã¿åããã§å®çŸããŸãã
const SUBJECT = {
Math: 'Math',
English: 'English',
Science: 'Science'
} as const;
type Subject = typeof SUBJECT[keyof typeof SUBJECT];
// "Math" | "English" | "Science" å
function getSubjectName(subject: Subject): string {
return subject;
}
getSubjectName("Math"); // â
æ£åžž
getSubjectName("History"); // â åãšã©ãŒïŒ
ãã®ãã¿ãŒã³ã¯ä»¥äžã®ããã«åäœããŸãïŒ
-
typeof SUBJECTã§ãªããžã§ã¯ãåãååŸ -
keyof typeof SUBJECTã§ããŒçŸ€ïŒâMathâ,âEnglishâ,âScienceâïŒãæœåº -
typeof SUBJECT[keyof typeof SUBJECT]ã§å€çŸ€ã®ãªãã©ã«åããŠããªã³ãšããŠåœ¢æ
ãžã§ããªãã¯ãš keyof ã®å®å掻çšã¡ãªãã
åã®å®å
šæ§åäžïŒã³ã³ãã€ã«æã«ååšããªãããããã£ã¢ã¯ã»ã¹ãé²ããŸãã
ã³ãŒãåå©çšæ§ïŒäžã€ã®é¢æ°ãã¯ã©ã¹ãæ§ã
ãªåã«å¯ŸããŠåå©çšã§ããŸãã
ä¿å®æ§æ¹åïŒåãæç¢ºãªã®ã§ãªãã¡ã¯ã¿ãªã³ã°æã®å®å
šç¶²ãšãªããŸãã
IDE ãµããŒã匷åïŒèªåè£å®ãšåãã³ããæ£ç¢ºã«æ©èœããŸãã
å®åã®ãã³ã
åçããŒã¢ã¯ã»ã¹ãŠãŒãã£ã«ïŒäŸïŒgetPropertyãsetPropertyãgetNestedPropertyïŒãäœã£ãŠãããšãããžã§ã¯ãå
šäœã§åå©çšã§ããã©ã³ã¿ã€ã ãšã©ãŒãã³ã³ãã€ã«ã¿ã€ã ãžç§»ããŸãã
ãããã質å (FAQ)
ãžã§ããªãã¯å倿°ã¯ããã€ãŸã§äœ¿ããŸããïŒ
å¿ èŠãªã ã䜿ããŸãããé床ãªå倿°ã¯å¯èªæ§ãæããããéåžžã¯2ïœ3åãé©åã§ãã
function transform<T, U, V>(input: T, mapper1: (x: T) => U, mapper2: (x: U) => V): V {
return mapper2(mapper1(input));
}
keyof ã¯ãã€äœ¿ãã®ãè¯ãã§ããïŒ
åçããããã£ã¢ã¯ã»ã¹ããããã³ã°ïŒå€æãŠãŒãã£ã«ãåå®å šãªã€ãã³ããã³ãã©ãç¶æ 管çãªã©ã§ããããã£ã®æå¹æ§ãä¿èšŒããããšãã«æçšã§ãããªããžã§ã¯ãã®ããããã£ãžå®å šã«ã¢ã¯ã»ã¹ããå¿ èŠããããšãã«ç¹ã«åšåãçºæ®ããŸãã
ãžã§ããªãã¯å¶çŽãããŸãã«ãè€éã«ãªã£ããã©ãããã°è¯ãã§ããïŒ
åãšã€ãªã¢ã¹ã§å¶çŽãåé¢ããŠå¯èªæ§ãäžããŸãããã
type ValidKey<T> = keyof T;
type ValidValue<T, K extends ValidKey<T>> = T[K];
function update<T, K extends ValidKey<T>>(
obj: T,
key: K,
value: ValidValue<T, K>
): void {
obj[key] = value;
}
ãããžã§ã¯ãã«é©çšããŠã¿ãŠãã ãã
ãžã§ããªãã¯ãš keyof ã¯åå®å
šæ§ãšã³ãŒãå質ã倧ããé«ãã匷åãªããŒã«ã§ããå°ããªãŠãŒãã£ã«ããé©çšç¯å²ãåºããŠã¿ãŸããããå®åã§ãªããžã§ã¯ãã®ããããã£ã«ã¢ã¯ã»ã¹ããã³ãŒããããã°ããã®ç®æãããžã§ããªãã¯ãš keyof ãé©çšããè¯ãã¹ã¿ãŒããã€ã³ãã§ããã³ãŒããæžããŠããŠããã®ããããã£ãæ¬åœã«ååšããŠãããèªä¿¡ããªãããšæãããããã®ã¿ã€ãã³ã°ãããžã§ããªãã¯å¶çŽã远å ããã¿ã€ãã³ã°ã§ããTypeScript ã®åã·ã¹ãã ãããªãã®ã³ãŒããããå®å
šã«ããŠãããŸã :)