前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >TS - Index Signatures

TS - Index Signatures

作者头像
前端黑板报
发布2024-06-14 20:29:10
710
发布2024-06-14 20:29:10
举报
文章被收录于专栏:前端黑板报

TS - Index Signatures

你有 2 个描述,软件开发人员薪水的对象:

代码语言:javascript
复制
const salary1 = {  

    baseSalary: 100_000,  
    
    yearlyBonus: 20_000  

};  

  

const salary2 = {  

    contractSalary: 110_000  

};

您想实现一个根据工资对象返回总薪酬的函数:

代码语言:javascript
复制
function totalSalary(salaryObject: ???) {  

    let total = 0;  
    
    for (const name in salaryObject) {  
    
        total += salaryObject[name];  
    
    }  
    
    return total;  

}  

console.log(totalSalary(salary1)); // => 120_000  

console.log(totalSalary(salary2)); // => 110_000

您将如何注释totalSalary()函数的salaryObject参数以接受键为字符串、值为数字的对象?

答案是使用索引签名!

让我们找到什么是TypeScript索引签名以及何时需要它们。

1.为什么要索引签名

索引签名的思想是在您只知道键和值类型时键入未知结构的对象。

索引签名适合薪水参数的情况:该函数应该接受不同结构的薪水对象-只需确保对象值是数字。

让我们用索引签名注释salaryObject参数:

代码语言:javascript
复制
function totalSalary(salaryObject: { [key: string]: number }) {  

    let total = 0;  
    
    for (const name in salaryObject) {  
    
        total += salaryObject[name];  
    
    }  
    
    return total;  

}  

console.log(totalSalary(salary1)); // => 120_000  

console.log(totalSalary(salary2)); // => 110_000

{ [key: string]: number }是索引签名,它告诉TypeScriptsalaryObject必须是一个以stringtype作为键和numbertype作为值的对象。

现在totalSalary()接受salary1salary2对象作为参数,因为它们是具有数字值的对象。

但是,该函数不会接受具有例如字符串作为值的对象:

代码语言:javascript
复制
const salary3 = {  

    baseSalary: '100 thousands'  

};  

// Type error:  

// Argument of type '{ baseSalary: string; }' is not assignable to parameter of type '{ [key: string]: number; }'.  

// Property 'baseSalary' is incompatible with index signature.  

// Type 'string' is not assignable to type 'number'.  

totalSalary(salary3);

2.索引签名语法

索引签名的语法很简单,看起来类似于属性的语法。但有一个区别:将键的类型写在方括号内:{ [key: KeyType]: ValueType }

以下是索引签名的几个示例。

stringtype是键和值:

代码语言:javascript
复制
interface StringByString {  

    [key: string]: string;  

}  

const heroesInBooks: StringByString = {  

    'Gunslinger': 'The Dark Tower',  
    
    'Jack Torrance': 'The Shining'  

};

string类型是键,值可以是stringnumberboolean

代码语言:javascript
复制
interface Options {  

    [key: string]: string | number | boolean;  
    
    timeout: number;  

}  

const options: Options = {  

    timeout: 1000,  
    
    timeoutMessage: 'The request timed out!',  
    
    isFileUpload: false  

};

Options接口还有一个字段timeout,它在索引签名附近工作正常。

索引签名的键只能是stringnumbersymbol。不允许其他类型:

代码语言:javascript
复制
interface OopsDictionary {  

// Type error:  

// An index signature parameter type must be 'string', 'number',  

// 'symbol', or a template literal type.  

    [key: boolean]: string;  

}

3.索引签名警告

TypeScript中的索引签名有一些您应该注意的注意事项。

3.1不存在的财产

如果您尝试访问索引签名为{ [key: string]: string }的对象的不存在属性会发生什么?

正如预期的那样,TypeScript将值的类型推断为string。但是如果您检查运行时值-它是undefined

代码语言:javascript
复制
interface StringByString {  

    [key: string]: string;  

}  

const object: StringByString = {};  

const value = object['nonExistingProp'];  

console.log(value); // => undefined

value根据TypeScript,变量是string类型,但是,它的运行时值是undefined

索引签名将键类型映射到值类型-仅此而已。如果您不正确映射,值类型可能会偏离实际的运行时数据类型。

为了使键入更准确,请将索引值标记为stringundefined。这样做,TypeScript会意识到您访问的属性可能不存在:

代码语言:javascript
复制
interface StringByString {  

    [key: string]: string | undefined;  

}  

const object: StringByString = {};  

const value = object['nonExistingProp'];  

console.log(value); // => undefined

3.2字符串和数字键

假设您有一本数字名称字典:

代码语言:javascript
复制
interface NumbersNames {  

    [key: string]: string  

}  

const names: NumbersNames = {  

    '1': 'one',  
    
    '2': 'two',  
    
    '3': 'three',  
    
    // etc...  

};

通过字符串键访问值按预期工作:

代码语言:javascript
复制
const value1 = names['1']; // OK

如果您通过数字1访问值会出错吗?

代码语言:javascript
复制
const value2 = names[1]; // OK  

没有,都很好!

当在属性访问器中用作键时,JavaScript会将数字隐式强制转换为字符串(names[1]names['1']相同)。TypeScript也执行这种强制。

您可以认为[key: string][key: string | number]相同。

4.索引签名与记录

TypeScript有一个实用程序类型Record<Keys, Values>来注释记录,类似于索引签名。

代码语言:javascript
复制
const object1: Record<string, string> = { prop: 'Value' }; // OK  

const object2: { [key: string]: string } = { prop: 'Value' }; // OK

最大的问题是…什么时候使用Record<Keys, Values>以及什么时候使用索引签名?乍一看,它们看起来很相似!

如您之前所见,索引签名仅接受stringnumbersymbol作为密钥类型。例如,如果您尝试使用字符串文字类型的并集作为索引签名中的键,则会出错:

代码语言:javascript
复制
interface Salary {  

// Type error:  

// An index signature parameter type cannot be a literal type or generic type.  

// Consider using a mapped object type instead.  

    [key: 'yearlySalary' | 'yearlyBonus']: number  

}

这种行为表明_索引签名在键方面是通用的。_

但是您可以使用字符串文字的并集来描述Record<Keys, Values>中的键:

代码语言:javascript
复制
type SpecificSalary = Record<'yearlySalary'|'yearlyBonus', number>  

type GenericSalary = Record<string, number>  

  

const salary1: SpecificSalary = {  

    'yearlySalary': 120_000,  
    
    'yearlyBonus': 10_000  

}; // OK

如果您想将键限制为特定字符串的并集,则Record<'prop1' | 'prop2' | ... | 'propN', Values>是替代索引签名的方法。

5.结论

当您不知道对象的确切结构,但您知道键和值类型时,索引签名注释非常适合这种情况。

索引签名由方括号中的索引名称及其类型组成,后跟冒号和值类型:{ [indexName: Keys]: Values }Keys可以是stringnumbersymbol,而Values可以是任何类型。

要将键类型限制为特定的字符串并集,则使用Record<Keys, Values>utilty类型是一个更好的主意。索引签名不支持字符串文字类型的并集。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端黑板报 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • TS - Index Signatures
    • 1.为什么要索引签名
      • 2.索引签名语法
        • 3.索引签名警告
          • 3.1不存在的财产
          • 3.2字符串和数字键
        • 4.索引签名与记录
          • 5.结论
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档