aono1234
@aono1234

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

TypeScriptのジェネリクスでエラーになる

Q&A

Closed

TypeScriptのジェネリクスを使うとエラーになる

以下コードの2箇所でエラーが発生してしまいます。

このコードは参加者にそれぞれエントリーナンバー(id)と点数が振られており、その点数で対戦をして
firstBattleとsecondBattleで勝ったもの同士が決勝に進みthirdWinnerになるというようなコードです。
トーナメント戦を意識しています。

const entryNumbers = [3, 6, 7, 9]
const timeTakens = [3000, 500, 600, 700]

const getResult = <T extends number> (choiceNum: T, entryNumbers: T[], timeTaken: T[]): T[] => {
  const selectedInedexNum: T = entryNumbers.indexOf(choiceNum) //エラー発生
  return [entryNumbers[selectedInedexNum], timeTaken[selectedInedexNum]]
}

const battle = <T extends number>(player1Num: T, player2Num: T, entryTable: T[], resultTable: T[]): T[] => {
  const player1 = getResult<number>(player1Num, entryNumbers, timeTakens)
  const player2 = getResult<number>(player2Num, entryNumbers, timeTakens)
  return(player1[1] > player2[1] ? player1 : player2) //エラー発生
}

const firstBattle = [3, 6]
const secondBattle = [7, 9]

const firstWinner:number[] = battle<number>(firstBattle[0], firstBattle[1], entryNumbers, timeTakens)
const secondWinner:number[] = battle<number>(secondBattle[0], secondBattle[1], entryNumbers, timeTakens)
const thirdWinner:number[] = battle<number>(firstWinner[0], secondWinner[0], entryNumbers, timeTakens)

console.log(firstWinner)
console.log(secondWinner)
console.log(thirdWinner)

エラー部分にホバーして出てきたエラーは以下です。
selectedInedexNumにホバーした結果

Type 'number' is not assignable to type 'T'.
  'number' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'number'.(2322)
const selectedInedexNum: T extends number

return(player1[1] > player2[1] ? player1 : player2)にホバーした結果

Type 'number[]' is not assignable to type 'T[]'.
  Type 'number' is not assignable to type 'T'.
    'number' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'number'.(2322)

TypeScriptは勉強し始めたばかりで全然慣れていません…
ジェネリクスを使わずに、Tのところを全てnumberとすればエラーにならないのですが…
すみませんが、ご教授頂けると幸いです。

0

1Answer

まず1つ目のエラーですが、配列のindexOfは添字を返すので、型はnumberです。
selectedInedexNumの型をnumberにすることで解消されます。

const selectedInedexNum: number = entryNumbers.indexOf(choiceNum)

2つ目のエラーですが、getResult<number>の戻り値の型はnumber[]になります。
battleの戻り値の型がT[]となっているところにnumber[]を返そうとしていることへのエラーです。

const battle = <T extends number>(player1Num: T, player2Num: T, entryTable: T[], resultTable: T[]): T[] => {
  const player1 = getResult<number>(player1Num, entryNumbers, timeTakens)
  const player2 = getResult<number>(player2Num, entryNumbers, timeTakens)
  return(player1[1] > player2[1] ? player1 : player2) //エラー発生
}

getResult<T>とすることで解消されます。(ただし他のところがエラーになりますが・・・)

ここからは私の解釈になりますが、Tに対してnumberを指定するとエラーになるのは、T extends numberというのは「Tnumber」ですが「numberT」ではないからです。
別の例として犬 extends 動物で考えると、「犬は動物」ですが「動物は犬」ではありません。

// 犬 extends 動物
// 猫 extends 動物
const myAnimal: 動物 = ; // 猫は動物👍
const myDog:  = myAnimal; // 動物(猫)は犬ではない👎

なので、変数や戻り値の型がTとなっているところでnumberを指定すると、「タイプ'number'は、タイプ'T'に割り当てることはできません」というエラーになります。

2Like

Comments

  1. @aono1234

    Questioner

    ありがとうございます!extendsに関してまだ勉強不足なところがあると痛感しました。1つ目のエラーを解決頂きありがとうございます。2つ目はおっしゃる通り別のエラーが出てしまったので、引き続き調査したいと思います。

Your answer might help someone💌