Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeScript Handbook - 3 - Index signature #356

Open
chochinlu opened this issue Jan 24, 2022 · 0 comments
Open

TypeScript Handbook - 3 - Index signature #356

chochinlu opened this issue Jan 24, 2022 · 0 comments

Comments

@chochinlu
Copy link
Owner

chochinlu commented Jan 24, 2022

https://dmitripavlutin.com/typescript-index-signatures/

應用場景

例如你現在有兩個object, 表示各自的薪水:

const salary1 = {
  baseSalary: 100_000,
  yearlyBonus: 20_000
};
 
const salary2 = {
  contractSalary: 110_000
};

你想弄個function計算各自的薪水總合:

function totalSalary(salaryObject: ???) {
  let total = 0;
  for (const name in salaryObject) {
    total += salaryObject[name];
  }
  return total;
}
totalSalary(salary1); // => 120_000
totalSalary(salary2); // => 110_000

salaryObject 的 type應該用什麼呢?

這時候就可以用 index signature:

function totalSalary(salaryObject: { [key: string]: number }) {
  let total = 0;
  for (const name in salaryObject) {
    total += salaryObject[name];
  }
  return total;
}
 
totalSalary(salary1); // => 120_000
totalSalary(salary2); // => 110_000

{ [key: string]: number } 就是 index signature

用來告訴 TypeScript salaryObject 都用 string 當作key, 然後 number 當作 value .

如果你用以下就會錯了:

const salary3 = {
  baseSalary: '100 thousands'
};
 
totalSalary(salary3);

陷阱1 : 檢查undefined

interface StringByString {
  [key: string]: string;
}
 
const object: StringByString = {};
 
const value = object['nonExistingProp'];
value; // => undefined. 可是會顯示 const value: string !!

這樣type沒有檢查出來! 唯一的方式, 就是多在 index signature 多標記:

interface StringByString {
  [key: string]: string | undefined;
}
 
const object: StringByString = {};
 
const value = object['nonExistingProp'];
value; // => undefined.  這樣就會顯示 const value: string | undefined

陷阱二: key的強制型別轉換

interface NumbersNames {
  [key: string]: string
}
 
const names: NumbersNames = {
  '1': 'one',
  '2': 'two',
  '3': 'three',
  // etc...
};

你用: const value2 = names[1]; 也是一點問題也沒有!

因為 JavaScript 如果你用number當key的時候, 會強制將number轉換為string

所以, TypeScript也遵守這樣的規則

要用 Index Signature 還是 Record<Keys, Type>

index signature 只能用 literal type 或是 generic type

所以你要用 複合式type, 那就用 Record

interface Salary {
  [key: 'yearlySalary' | 'yearlyBonus']: number
}

會告知: An index signature parameter type cannot be a literal type or generic type. Consider using a mapped object type instead.

改成這樣就可以了:

type SpecificSalary = Record<'yearlySalary'|'yearlyBonus', number>
 
const salary1: SpecificSalary = { 
  'yearlySalary': 120_000,
  'yearlyBonus': 10_000
}; // OK
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant