みなさんこんにちは。宮水です。
今日は、TypeScript エクササイズの3に取り組んでみました。
英語も苦手なので、翻訳も自分でしてみました。
こちらのリポジトリをforkして、cloneして取り組みます。
rootディレクトリで、yarn installしてから問題文にあるRun this exerciseのコマンドを叩くと、答え合わせができます。すごい!!
github.com
前回の問題
本日の問題
import chalk from 'chalk'; /* Intro: As we introduced "type" to both User and Admin it's now easier to distinguish between them. Once object type checking logic was extracted into separate functions isUser and isAdmin - logPerson function got new type errors. UserとAdminの両方に「type」を導入したので、簡単にそれらを区別できるようになりました。 オブジェクトのtypeをチェックするロジックがisUserとisAdminに分けられると、logPerson関数で新しいタイプのエラーが発生しました。 Exercise: Figure out how to help TypeScript understand types in this situation and apply necessary fixes. TypeScriptが型を理解するために、必要な修正を適用してください。 Run: npm run 3 - OR - yarn -s 3 */ interface User { type: 'user'; name: string; age: number; occupation: string; } interface Admin { type: 'admin'; name: string; age: number; role: string; } type Person = User | Admin; const persons: Person[] = [ { type: 'user', name: 'Max Mustermann', age: 25, occupation: 'Chimney sweep' }, { type: 'admin', name: 'Jane Doe', age: 32, role: 'Administrator' }, { type: 'user', name: 'Kate Müller', age: 23, occupation: 'Astronaut' }, { type: 'admin', name: 'Bruce Willis', age: 64, role: 'World saver' } ]; function isAdmin(person: Person) { return person.type === 'admin'; } function isUser(person: Person) { return person.type === 'user'; } function logPerson(person: Person) { let additionalInformation: string = ''; if (isAdmin(person)) { additionalInformation = person.role; } if (isUser(person)) { additionalInformation = person.occupation; } console.log(` - ${chalk.green(person.name)}, ${person.age}, ${additionalInformation}`); } console.log(chalk.yellow('Admins:')); persons.filter(isAdmin).forEach(logPerson); console.log(); console.log(chalk.yellow('Users:')); persons.filter(isUser).forEach(logPerson); // In case if you are stuck: // https://www.typescriptlang.org/docs/handbook/advanced-types.html#using-type-predicates
答え
interface User { type: 'user'; name: string; age: number; occupation: string; } interface Admin { type: 'admin'; name: string; age: number; role: string; } type Person = User | Admin; const persons: Person[] = [ { type: 'user', name: 'Max Mustermann', age: 25, occupation: 'Chimney sweep' }, { type: 'admin', name: 'Jane Doe', age: 32, role: 'Administrator' }, { type: 'user', name: 'Kate Müller', age: 23, occupation: 'Astronaut' }, { type: 'admin', name: 'Bruce Willis', age: 64, role: 'World saver' } ]; const isAdmin = (person: Person): person is Admin => person.type === 'admin'; const isUser = (person: Person): person is User => person.type === 'user'; function logPerson(person: Person) { let additionalInformation: string = ''; if (isAdmin(person)) { additionalInformation = person.role; } if (isUser(person)) { additionalInformation = person.occupation; } console.log(` - ${chalk.green(person.name)}, ${person.age}, ${additionalInformation}`); } console.log(chalk.yellow('Admins:')); persons.filter(isAdmin).forEach(logPerson); console.log(); console.log(chalk.yellow('Users:')); persons.filter(isUser).forEach(logPerson)
解説&感想
今回は、isの問題でした。
自分の経験では解けなくて、問題文一番下にある公式ドキュメントのヒントを見ました。
www.typescriptlang.org
TypeScriptが引数で受け取ったの型を推測できない場合、私たちがこうやって書いてTypeScriptを助けてあげる必要もあるんですね。
// このpersonはAdminだよ! const isAdmin = (person: Person): person is Admin => person.type === 'admin';
公式ドキュメントの同じ項目にinというものもあって、これは逆に"swim"はFishかBirdのプロパティだよ!と教えてあげることができます。
isとはちょっと違うけど、型を限定できるというものです。
function move(pet: Fish | Bird) { if ("swim" in pet) { return pet.swim(); } return pet.fly(); }
うーん、だんだん難しくなってきました。以上です!