ウェブサイト検索

TypeScriptにおけるスプレッド演算子による型定義の削除


TypeScriptでこの奇妙な現象に遭遇しました。スプレッド演算子を使用すると、型チェックが失われるようです。これにはエラーが発生すると思っていました:

interface Input {
  thingOne: string;
  thingTwo: number;
  thingThree: string;
  thingFour: boolean;
  thingFive: Array<number>
}

interface Output {
  thingThree: string;
  thingFour: boolean;
  thingFive: Array<number>
}

const transformFunction = (input: Input): Output => {
  const result: Output = {
    ...input,
    thingFour: !input.thingFour
  }
  return result
}

TypeScript プレイグラウンドの例

私は result を Output として入力していますが、そこに Input 型のオブジェクトを展開すると、明らかに Output 型ではない結果が生成されます。なぜ TypeScript はこれを検出しないのでしょうか?

回答 #1

ここで私たちが期待しているのは、TypeScriptの余分なプロパティチェック機能をトリガーすることです。この機能は、オブジェクトの型を明示的に指定した場合に、そのオブジェクトに余分なプロパティがあるとTypeScriptが警告することを教えてくれます。残念ながら、これはオブジェクトリテラルにのみ機能します。

例えばこれ:

const transformFunction = (input: Input): Output => {
  return {
    thingOne: "string;",
    thingTwo: 123,
    thingThree: "string;",
    thingFour: !input.thingFour,
    thingFive: [1, 23],
  };
};

警告:

Type '{ thingOne: string; thingTwo: number; thingThree: string; thingFour: boolean; thingFive: number[]; }' is not assignable to type 'Output'.
  Object literal may only specify known properties, and 'thingOne' does not exist in type 'Output'.

スプレッド演算子の場合は、excesプロパティのチェックに含まれていないようです。こちらを参照してください: https://github.com/microsoft/TypeScript/issues/41237

これは余剰プロパティのチェックです。@RyanCavanaugh によれば、これはタイプシステムの一部というよりはむしろリンターのようなものです。しかし、あなたが気づいたように、すべてのケースがこのチェックでカバーされているわけではありません。

彼らはまた、正確な型に関する進行中の変換をここで確認することについて言及しました: https://github.com/microsoft/TypeScript/issues/12936

回答 #2

この関数は型的に正しいです。なぜなら、型 Input は余分なプロパティがあっても問題なく型 Output に代入できるからです。リテラルオブジェクトの場合のみ、余分なプロパティのチェックが行われます。これは、オブジェクトリテラルに余分なプロパティがある場合、それが間違いである可能性が非常に高いためです。例えば、この定数を考えてみてください。

const o: {a: number} = {a: 1, b: 2}

現在、o は型 {a: number} を持っているため、b プロパティに型付きでアクセスする方法はなく、TypeScript はこれをエラーと見なします。

関連記事