Open17

実践TypeScript 吉井 健文 (著) を読んでわからなかったことをメモしておくところ

りさきゃんりさきゃん

🤔 3-5-1 でエラーが表示されて tsc 実行できない。
error TS2585: 'Promise' only refers to a type, but is being used as a value here. Do you need to change your target library? Try changing thelib compiler option to es2015 or later.
target library ってどの library のことだろう。

りさきゃんりさきゃん

非同期処理を行うためのPromiseはEMCAScript 2015で仕様に追加されたので、tsconfig.json のtargetLibrary をes2015以降にして tsc する必要があったというだけだった。

りさきゃんりさきゃん

🛡 Type guard 🛡

function greet(name?: string) {
  if (name == undefined) return "Hello" // Type Guard
  return `Hello ${name.toUpperCase()}`
}

console.log(greet())
console.log(greet("taro"))
りさきゃんりさきゃん

Excess Property Checks

変数を渡すのとオブジェクトリテラルを引数に直接記述するのとで挙動が変わる
やばくない・・・?
関数呼び出し時に直接呼ぶのが設定値を渡すシーンで多く使われるので、「あんたこれ設定にない値だけど大丈夫なの?」という感じで過剰に検査するようになっているとのこと。
初見殺し‥

type User = {
  age?: number,
  name?: string,
}

const notUser = {
  gender: "male",
  graduate: "Tokyo"
}

const maybeUser = {
  age: 26,
  name: "taro",
  gender: "male"
}
function registerUser(user: User) { }
// registerUser(notUser) エラーになる。これはわかる。


registerUser(maybeUser)
// 同じ内容だけど直接値を渡すとエラーになる。初見殺し。
// registerUser(
//   {
//     age: 26,
//     name: "taro",
//     gender: "male"
//   }
// )

りさきゃんりさきゃん

... っていうオブジェクトスプレッドというのを使うと変数を使うときと同じでエラーにならない。なんだと。。。

registerUser(
  {
    ...
    {
      age: 26,
      name: "taro",
      gender: "male"
    }
  }
)
りさきゃんりさきゃん

🔝 トップレベルプロパティ 🔝

インデックスシグネチャのnumberとstringに互換性がないため。

type User1 = {
  name: string // <- エラーになる
  [k: string]: number
}
const userA: User1 = {
  name: "Taro",
  age: 26
}

[k: string]: number | string インデックスシグネチャの型を Union Types にする。

type User1 = {
  name: string // <- エラーにならない
  [k: string]: number | string  // <- インデックスシグネチャの型を Union Types に
}
const userA: User1 = {
  name: "Taro",
  age: 26
}
りさきゃんりさきゃん

リスト4-2-15実行時のエラー

interface User15 {
  [k: string]: any
}

const user15: User15 = {
  name: "Taro",
  age: 28,
  walk: () => { },
  talk: async () => { },
}

An async function or method in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your --lib option.ts(2705)

りさきゃんりさきゃん
interface User16 {
  [k: string]: Promise<any>
}

const user16: User16 = {
  // name: "Taro",
  // age: 28,
  // walk: () => { },
  talk: async () => { }
}
src/4-2/4-2-16.ts:9:9 - error TS2739: Type '() => Promise<void>' is missing the following properties from type 'Promise<any>': then, catch, [Symbol.toStringTag]

9   talk: async () => { }
          ~~~~~~~~~~~~~~~

  src/4-2/4-2-16.ts:9:9
    9   talk: async () => { }
              ~~~~~~~~~~~~~~~
    Did you mean to call this expression?


Found 1 error.

tsconfigでは "target": "ES2015"を指定。

解決

interface でも関数だよーってことを書いてあげないといけなかった

interface User16 {
  [k: string]: () => Promise<any> // 🈁
}

const user16: User16 = {
  // name: "Taro",
  // age: 28,
  // walk: () => { },
  talk: async () => {}
}

りさきゃんりさきゃん
function greet23(): any {
  console.log("hello")
}
const message23 = greet23()
console.log(message23.toUpperCase())

返り値がないのにtoUpperCaseをよんでるけどエラー出てない。

実行すると…ランタイムエラー
any を指定したことで戻り値がないよを示すvoidが相殺されていた。anyを付与しなければエラーが出てくれる。

function greet23() {
  console.log("hello")
}
const message23 = greet23()
// console.log(message23.toUpperCase()) エラーになってくれる

りさきゃんりさきゃん

⚠️ Non-null assertion

null および undefined ではない状況が信頼できない限り使わない。

りさきゃんりさきゃん

5章 {}型 の読み方について社内の神に聞いたところ、

普段だったら オブジェクト型 と読む
でも、TS だと object 型 も存在する
TS文脈だったら、オブジェクトリテラル型が良さそう

との神回答を頂いた

りさきゃんりさきゃん

interface は open ended に準拠しているので、型拡張ができる。
type alias はよくみる type User = {name: string} みたいなやつ。

りさきゃんりさきゃん

ReactとTypeScriptを一緒に使うことで、末端まで型をチェックできるから、修正による考慮外の挙動を減らせる。一緒に使うメリット。