Indexed Access Inference Improvements
TL;DR
オブジェクトがクロージャに渡った時の型推論が正しく動作するようになった。
前提
ログ書き込みをサンプルとする。
interface LogOperation {
loggedIn: {
date: Date;
userName: string;
};
switchRole: {
beforeRole: string;
afterRole: string;
};
}
ログ書き込み部分を共通化し、テキストと整形をパラメータで渡す。
/* ==================================================
"ringtail003 logged in at 2023/01/31 10:11:12"
================================================== */
writeLog({
operation: 'loggedIn',
value: {
date: new Date(),
userName: 'ringtail003',
},
format: (value) =>
`${value.userName} logged in at ${value.date.toLocaleString()}`,
});
/* ==================================================
"Switch STAFF to ADMIN"
================================================== */
writeLog({
operation: 'switchRole',
value: {
beforeRole: 'staff',
afterRole: 'admin',
},
format: (value) =>
`Switch ${value.beforeRole} to ${value.afterRole}`,
});
共通化のコードは以下のもの。肝は operation
で「操作」を特定し、format
に該当する「値」が渡ることにある。
function writeLog<K extends keyof LogOperation>(log: LogFormat<K>) {
fs.writeFileSync(
'yyyy-MM-dd.log',
log.format(log.value)
);
}
type LogFormat<P extends keyof LogOperation> = {
[K in P]: {
operation: K; // <===== loggedIn | switchRole が入る
value: LogOperation[K];
format: (p: LogOperation[K]) => void; // <===== loggedIn なら date を持っている
};
}[P];
Previous
クロージャのパラメータの型推論が弱かった。
writeLog({
kind: 'loggedIn',
value: ...,
format: (value) =>
`${value.userName} logged in at ${value.date.toLocaleString()}`,
// ❌ ERROR! userName does not exists
// ❌ ERROR! date does not exists
});
Current
クロージャのパラメータが正しく推論されるようになった。
writeLog({
kind: 'loggedIn',
value: ...,
format: (value) =>
`${value.userName} logged in at ${value.date.toLocaleString()}`,
// ✅ PASS! userName: string
// ✅ PASS! date: Date
});
Last updated