ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

[TypeScript学习笔记-03]常用类型解读

[TypeScript学习笔记-03]常用类型解读 1. 三种原生类型primitivesJavaScript 中有三种非常常用的基本类型字符串、数字和布尔值。每种类型在 TypeScript 中都有对应的类型。正如你所预料的如果你对这些类型的值使用 JavaScript 的typeof运算符你会看到相同的名称string表示字符串值例如“Hello, world”number表示数字例如 42。JavaScript 没有专门的运行时整数值因此没有与int或float等效的整数类型——所有类型都只是numberboolean表示true和false这两个值。2. 数组Array两种表示方法T[]:number[]、string[]和boolean[]等ArrayT:Arraynumber、Arraystring和Arrayboolean等。3. any当你不希望某个特定值导致类型检查错误时可以使用它。当一个值的类型为any时你可以访问它的任何属性这些属性本身也是any类型像调用函数一样调用它将其赋值给或从任何类型的值或者几乎做任何其他语法上合法的事情。当您不指定类型且 TypeScript 无法从上下文中推断类型时编译器通常会默认使用 any 类型。不过通常你应该避免这种情况因为any不会进行类型检查。使用编译器标志--noImplicitAny可以将任何隐式的any标记为错误。4. 函数Function参数类型标注functiongreet(name:string){console.log(Hello, name.toUpperCase()!!);}返回类型标注functiongetFavoriteNumber():number{return26;}注:与变量类型注解类似通常不需要返回值类型注解因为 TypeScript 会根据函数的返回语句推断其返回类型。上面示例中的类型注解不会改变任何内容。有些代码库会出于文档编写、防止意外更改或个人偏好等目的显式指定返回值类型。异步函数asyncfunctiongetFavoriteNumber():Promisenumber{return26;}匿名函数constnames[Alice,Bob,Eve];// Contextual typing for function - parameter s inferred to have type stringnames.forEach(function(s){console.log(s.toUpperCase());});// Contextual typing also applies to arrow functionsnames.forEach((s){console.log(s.toUpperCase());});注即使参数s没有类型注解TypeScript 也使用了forEach函数的类型以及数组的推断类型来确定s的类型。这个过程被称为上下文类型化因为函数发生的上下文决定了它应该是什么类型。5. 对象Object对象指的是任何带有属性的 JavaScript 值几乎涵盖了所有 JavaScript 值要定义一个对象类型我们只需列出它的属性及其类型即可。functionprintCoord(pt:{x:number;y:number}){console.log(The coordinates x value is pt.x);console.log(The coordinates y value is pt.y);}printCoord({x:3,y:7});可缺省参数functionprintName(obj:{first:string;last?:string}){// Error - might crash if obj.last wasnt provided!console.log(obj.last.toUpperCase());// obj.last is possibly undefined.if(obj.last!undefined){console.log(obj.last.toUpperCase());}console.log(obj.last?.toUpperCase());}5. 联合Union联合类型是由两个或多个其他类型组成的类型它表示的值可以是其中任何一个类型。我们将这些类型分别称为联合体的成员。从集合角度来将就是取并集。functionprintId(id:number|string){console.log(Your ID is: id);}// OKprintId(101);// OKprintId(202);// ErrorprintId({myID:22342});TypeScript 只允许对联合体中的每个成员都有效的操作(联合类型的交集成员)执行。例如如果你有一个联合体string | number你就不能使用仅适用于字符串的方法。functionprintId(id:number|string){console.log(id.toUpperCase());//Property toUpperCase does not exist on type string | number.//Property toUpperCase does not exist on type number.}functiongetFirstThree(x:number[]|string){returnx.slice(0,3);}使用其它成员需要采用相应的Type Narrowing手段可以使用typeof对联合类型实施 Type NarrowingfunctionprintId(id:number|string){if(typeofidstring){// In this branch, id is of type stringconsole.log(id.toUpperCase());}else{// Here, id is of type numberconsole.log(id);}}可以使用Array.isArray对联合类型实施Type NarrowingfunctionwelcomePeople(x:string[]|string){if(Array.isArray(x)){// Here: x is string[]console.log(Hello, x.join( and ));}else{// Here: x is stringconsole.log(Welcome lone traveler x);}}6. 类型别名Alias经常需要多次使用同一种类型并用同一个名称来指代它。typePoint{x:number;y:number;};typeIDnumber|string;注别名仅仅是别名—不能使用类型别名来创建同一类型的不同版本。使用别名时其作用与直接编写别名类型完全相同。7. 接口接口声明是命名对象类型的另一种方式interfacePoint{x:number;y:number;}接口扩展与别名扩展interfaceAnimal{name:string;}interfaceBearextendsAnimal{honey:boolean;}typeAnimal{name:string;}typeBearAnimal{honey:boolean;}注从集合的角度来讲看起来实在拓展成员本质上在执行交集操作。可以直接向现有接口添加成员interfaceWindow{title:string;}interfaceWindow{ts:TypeScriptAPI;}8. 类型断言Type Assertion有时你会获得一些关于值类型的信息而 TypeScript 却无法知道这些信息。在这种情况下您可以使用类型断言来指定更具体的类型constmyCanvasdocument.getElementById(main_canvas)asHTMLCanvasElement;constmyCanvasHTMLCanvasElementdocument.getElementById(main_canvas);只允许类型断言转换为更具体或更不具体的类型版本。这条规则可以防止诸如以下不可能的类型强制转换constxhelloasnumber;//Conversion of type string to type number may be a mistake because neither type sufficiently overlaps with the other.// If this was intentional, convert the expression to unknown first.解决方案constaexprasanyasT;9. 字面量类型Literal 一种理解方式是考虑 JavaScript 如何声明变量。var和let都允许更改变量内部存储的内容而const则不允许。这体现在 TypeScript 如何为字面量创建类型上。letchangingStringHello World;// let changingString: stringconstconstantStringHello World;// const constantString: Hello World将字面量视为一种具有固定值的类型那么letx:hellohello;// OKxhello;// ...xhowdy;//Type howdy is not assignable to type hello.针对字面量类型的联合就好理解了可以视为枚举functionprintText(s:string,alignment:left|right|center){// ...}针对boolean类型的理解typebooleantrue|false当您使用对象初始化变量时TypeScript 会假定该对象的属性值之后可能会发生变化所以属性类型并不是字面量类型。constobj{counter:0};if(someCondition){obj.counter1;}所以不能使用非字面量类型属性成员为字面量类型参数赋值declarefunctionhandleRequest(url:string,method:GET|POST):void;constreq{url:https://example.com,method:GET};handleRequest(req.url,req.method);// Argument of type string is not assignable to parameter of type GET | POST.这个问题的两种解决方案解决方案1使用as将变量类型转换成更具体的字面量类型// Change 1:constreq{url:https://example.com,method:GETasGET};// Change 2handleRequest(req.url,req.methodasGET);解决方案2使用as将对象转换成const类型constreq{url:https://example.com,method:GET}asconst;handleRequest(req.url,req.method);as const 后缀的作用类似于 const但它是针对类型系统的确保所有属性都被赋予字面类型而不是像 string 或 number 这样的更通用的版本。10. null undefinedJavaScript 有两个原始值用于表示值缺失或未初始化null和undefined。TypeScript 中有两个同名的对应类型。这些类型的行为取决于你是否启用了--strictNullChecks选项。strictNullChecks off关闭--strictNullChecks后仍然可以正常访问可能为null或undefined的值并且可以将null和undefined值赋给任何类型的属性。这与没有空值检查的语言例如 C#、Java的行为类似。缺少对这些值的检查往往是导致 bug 的主要原因我们始终建议用户在代码库中条件允许的情况下启用strictNullChecks。strictNullChecks on启用strictNullChecks后当值为null或undefined时在使用该方法或属性之前需要先检查这些值是否为 null。就像在使用可选属性之前检查undefined一样我们可以使用范围缩小来检查可能为null的值functiondoSomething(x:string|null){if(xnull){// do nothing}else{console.log(Hello, x.toUpperCase());}}可以使用类似与C#的方式后缀。functionliveDangerously(x?:number|null){// No errorconsole.log(x!.toFixed());}11. SymbolJavaScript 的Symbol是一种独特的原始数据类型用来创建不可重复的唯一标识符常用于对象属性键以避免冲突。它既保证唯一性又能实现弱封装和信息隐藏。它具有如下特性唯一性每次调用Symbol()都会返回一个全新的、唯一的值类型typeof Symbol()返回 “symbol”不可用 newnew Symbol()会抛出TypeError只能直接调用Symbol()描述字符串可以传入一个字符串作为描述仅用于调试不影响唯一性。使用场景对象属性键避免与其他属性冲突且不会被常规枚举方法如for...in、Object.keys访问。弱封装隐藏内部实现细节。全局共享 Symbol通过Symbol.for(key)和Symbol.keyFor(symbol)使用全局注册表。并能被枚举constpasswordSymbol(password);constaccount{user_id:alice,email:aliceexample.com,[password]:password}for(constkeyinaccount){console.log(${key})}//输出//user_id//email
返回列表