Typescript 是 Microsoft 开发的一种编程语言,旨在为 Javascript 语言带来严格的类型检查和类型安全方面的安全性。它是 JavaScript 的超集,可以编译为 Javascript。编译选项是 tsconfig.json
文件中的属性,可以启用或禁用以改善 Typescript 体验。下面就来看看如何通过设置编译选项来提高 Typescript 代码的质量。
在 TypeScript 项目中,tsconfig.json
放在项目根目录,它指定了用来编译这个项目的根文件和编译选项。在 tsconfig.json
里有以下可配置项:
{
"compileOnSave": true,
"files": [],
"include": [],
"exclude": [],
"extends": "",
"compilerOptions": {}
}
这些配置项的作用如下:
compileOnSave
:如果设为 true
,在编辑了项目中文件保存的时候,编辑器会根据 tsconfig.json
的配置重新生成文件,不过这个需要编辑器支持。files
:可以配置一个数组列表,里面包含指定文件的相对或绝对路径。编译器在编译的时候只会编译包含在 files 中列出的文件。如果不指定,则取决于有没有设置 include 选项;如果没有 include 选项,则默认会编译根目录以及所有子目录中的文件。这里列出的路径必须是指定文件,而不是某个文件夹,而且不能使用*
、?
、**/
等通配符。include
:include 也可以指定要编译的路径列表,但和 files 的区别在于,这里的路径可以是文件夹,也可以是文件,可以使用相对和绝对路径,而且可以使用通配符。比如"./src"
即表示要编译 src 文件夹下的所有文件以及子文件夹的文件。exclude
:表示要排除的、不编译的文件,它也可以指定一个列表,规则和 include
一样,可以是文件可以是文件夹,可以是相对路径或绝对路径,可以使用通配符。extends
:可以通过指定一个其它的 tsconfig.json
文件路径,来继承这个配置文件里的配置,继承来的同名配置会覆盖当前文件定义的配置,所有相对路径都被解析为其所在文件的路径。TS 在 3.2 版本开始,支持继承一个来自 Node.js 包的 tsconfig.json
配置文件。compilerOptions
:用来设置编译选项,是 tsconfig.json
配置中最重要的配置项。本文所提到所有选项都需要写在这个配置项中。将这个选项设置为 true
时,编译器将检查未使用的局部变量并生成错误,其方式类似于 ESLint 中的 no-unused-vars
。此编译器选项旨在消除和删除 Typescript 中未使用的变量。考虑下面的例子:
const numHandler = (input: number) => {
let digits;
return input;
};
在上面的例子中,我们定义了一个名为 numHandler
的函数,它接受一个 number
类型的参数。接下来,定义并返回了input
参数。当编译上面的代码时,就会提示以下错误:
error TS6133: 'digits' is declared but its value is never read
产生这个错误的原因是声明了 digits
变量但并没有使用它。可以通过在代码中的某处使用声明的值,或者通过将 tsconfig.json
文件中的 noUnusedLocals
选项设置为 false
来消除此错误。
这个编译选项有点类似于 noUnusedLocals
选项。不同之处在于,noUnusedLocals
在有未使用的局部变量时产生错误,noUnusedParameter
在声明但未使用函数参数时产生错误。考虑下面的例子:
const anExample = (input: string) => {
const someStrings = 'name'
return { true, someStrings };
};
在上面的例子中,我们定义了一个名为 anExample
的函数,它接受一个 string
类型的参数。接下来,定义了一个名为 someStrings
的变量,然后返回一个布尔值和定义的变量。当编译上面的代码时,将会提示以下错误:
error TS6133: 'input' is declared but its value is never read
发生这种情况是因为在函数中声明了输入参数而没有使用它。可以通过使用函数体中声明的参数或将 tsconfig.json
文件中的 noUnusedParameter
选项设置为 false
来消除此错误。
这个编译选项确保任何带有返回声明的函数都返回一些内容。当函数中的代码路径不返回值时,此选项会生成错误。考虑下面的例子:
function add(input: number, output: number) {
if (input + output > 0) {
return input + output;
}
}
在上面的例子中,我们定义了一个带有两个 number
类型参数的函数。接下来,设置一个 if
语句,它检查两个参数的和是否大于零,然后返回该和。将此编译选项设置为 true
时,编译器会提示以下类型错误:
error TS7030: Not all code paths return a value.
Typescript 在这里检测到并非所有代码路径都返回某些内容。当参数的总和不是正数时,就会没有返回语句,这就可能会引发错误,因为上面的函数将返回 undefined
。要解决此问题,请确保代码的所有部分都会返回内容。可以这样进行修改:
function add(input: number, output: number) {
if (input + output > 0) {
return input + output;
}
return
}
通过使用 return
关键字,确保了代码的所有部分都返回一些内容。编译选项帮助我们检测可能的缺失情况,并避免错误。
当这个选项设置为 true
时,只要有 switch
语句中缺少 break
或 return
关键字,这个编译选项就会生成错误。考虑下面的例子:
let name = 'Isaac';
switch (name) {
case 'Mike':
console.log('name is Mike');
case 'John':
console.log('name is John');
break;
}
当编译上面的代码时,将会提示以下错误:
error TS7029: Fallthrough case in switch
发生这种情况是因为在第一个 switch
语句的分支中缺少了 break
关键字。
将这个编译选项设为 true
时,null
和 undefined
值不能赋值给非这两种类型的值,别的类型的值也不能赋给它们。除了 any
类型,还有个例外就是 undefined
可以赋值给 void
类型。这个选项可以帮助我们消除 Uncaught TypeError
错误。考虑下面的例子:
let title: string;
name = title;
console.log(name);
当编译上面的代码时,将会提示以下错误:
error TS2454: Variable 'title' is used before being assigned
解决这个错误的方法是在使用变量之前为其赋值:
let title: string = "Student"
name = title
console.log(name)
Typescript 中的每个变量都有一个类型。我们要么显式地定义类型,要么 Typescript 推断它的类型。考虑下面的例子:
function value(a) {
return;
}
在上面的代码中,有一个参数为 a
的函数。由于没有为该参数定义类型,因此 Typescript 推断该参数具有 any
类型。将此编译选项设置为 true
时,编译器会提示以下错误:
error TS7006: Parameter 'a' implicitly has an 'any' type
解决此问题的方法就是确保正确定义每个参数的类型。
将这个编译器选项设置为 true
时,Typescript 会在不正确地使用 this
关键字的情况下或在不清楚 this 所指的位置的地方提示错误。
class Person {
weight: number;
height: number;
constructor(weight: number, height: number) {
this.weight = weight;
this.height = height;
}
getBodyMassIndex() {
return function () {
return this.weight / (this.height * this.height);
};
}
}
由于 Javascript 中存在作用域,当编译上面的代码时,就会提示以下错误。这是因为 this
关键字的上下文默认没有绑定到任何 Person
实例。
error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation
解决这个问题的方法就是使用箭头函数,因为箭头函数使用其父级的执行上下文:
class Person {
weight: number;
height: number;
constructor(weight: number, height: number) {
this.weight = weight;
this.height = height;
}
getBodyMassIndex() {
return () => {
return this.weight / (this.height * this.height);
};
}
}
这个编译选项可以确保使用具有正确参数的 call()
、bind()
和 apply()
函数。
const numHandler = (a: number) ={
console.log(`log ${a}!`);
}
numHandler.call(undefined, 'Mike')
当把这个编译选项设置为 true
的情况下运行上述代码时,将会提示以下错误:
error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'
为了解决这个问题,需要传入正确的参数:
const numHandler = (a: number) ={
console.log(`log ${a}!`)
}
numHandler.call(undefined, '25')
将这个编译选项设置为 true
时,可以确保在构造函数中初始化所有类属性。
class User {
name: string;
age: number;
occupation: string | undefined;
constructor(name: string) {
this.name = name;
}
}
在上面的代码块中有一个 User
类,constructor()
方法是初始化其实例属性的地方。当实例化一个类对象时,JavaScript 会自动调用 constructor()
方法。Typescript 要求我们要么初始化定义的属性,要么指定一个 undefined
类型。因此,当编译上面的代码时,将会提示以下错误:
error TS2564: Property 'age' has no initializer and is not definitely assigned in the constructor.
在 Javascript 中,可以抛出错误并在 catch 中捕获它。通常这将是一个 error
实例,默认设置为 any
。将 useUnknownInCatchVariable
编译选项设置为 true
时,它会隐式地将 catch
中的任何变量设置为 unknown
而不是 any
。考虑下面的例子:
try {
throw 'myException';
}
catch (err) {
console.error(err.message);
}
当编译上述代码时,它会将 err 更改为 unknown 类型。因此会提示以下错误;
error TS2571: Object is of type 'unknown'.
产生此错误是因为 Typescript 将 err 设置为 unkown。可以通过以下方式来修复此错误:
err
从 unknown
缩小到 error
实例try {
throw 'myException';
}
catch (err) { // err: unknown
if (err instanceof Error) {
console.error(err.message);
}
}
try {
throw "myException";
} catch (err) {
// 错误现在缩小为一个字符串
if (typeof err === "string") {
console.error(err);
}
}
在 if 检查的帮助下,Typescript 识别出 typeof err === "string"
是一种特殊形式的代码,我们在其中显式声明和描述类型,这称为类型保护。
当 strictFunctionTypes
为 true
时,会更彻底地检查函数参数。Typescript 参数默认是双向协变的,这意味着它们既可以是协变的,也可以是逆变的。方差是一种深入了解子类型关系的方法。当参数是协方差时,我们可以将特定类型分配给更广泛的类型(例如将子类型分配给超类型)。逆变是相反的:可以将更广泛的类型分配给特定类型(例如将超类型分配给子类型)。
//strictFunctionTypes: false
interface Animal {
name: string;
}
interface Dog extends Animal {
breeds: Array<string>;
}
let getDogName = (dog: Dog) => dog.name;
let getAnimalName = (animal: Animal) => animal.name;
getDogName = getAnimalName; // Okay
getAnimalName = getDogName; // Okay
上面的代码运行时并没有提示错误,默认情况下参数是双向协变比较的。超类型 getAnimalName
和子类型 getDogName
的方法可以相互分配。如果 strictFunctionTypes
设置为 true
,则 Typescript 的参数进行逆变比较。
//strictFunctionTypes : true
interface Animal {
name: string;
}
interface Dog extends Animal {
breeds: Array<string>;
}
let getDogName = (dog: Dog) => dog.name;
let getAnimalName = (animal: Animal) => animal.name;
getDogName = getAnimalName; // Okay
getAnimalName = getDogName; // Error
当上面的代码运行时,将会提示以下错误:
Type '(dog: Dog) => string' is not assignable to type '(animal: Animal) => string'.
Types of parameters 'dog' and 'animal' are incompatible.
Property 'breeds' is missing in type 'Animal' but required in type 'Dog'.
这里,getAnimalName
是比 getDogName
更广泛的函数。因此,在这种情况下,无法将超类型分配给子类型。但是,可以将子类型分配给超类型。大多数时候,函数参数应该是逆变的,而不是双向协变的。如果启用这个编译选项,Typescript 将不会将函数参数视为双向协变。
UnReachable 的代码永远不会被执行,例如在 return
语句之后的代码。将将这个编译选项设置为 true
时,将忽略无法访问的代码。相比之下,TypeScript 会在 allowUnreachableCode
设置为 false
时验证我们的代码路径,确保所有代码都可以访问和使用。设置为 true
时,如果检测到任何无法访问的代码,则会引发错误。
const randomNum = (n: number): boolean => {
if (n > 5) {
return true;
} else {
return false;
}
return true;
};
如果代码被证明无法访问,Typescript 将提示以下警告:
error TS7027: Unreachable code detected.
当此编译选项设置为 true
时,它要求我们使用 []
括号表示法和 .
点符号表示法访问未知属性以访问已定义的属性。这提高了一致性,因为使用点符号访问的属性始终指示现有属性。obj.key
语法如果属性不存在,可以使用 [] 括号表示法:obj["key"]
。
interface HorseRace {
breed: "Shetland" | "Hackney" | "Standardbred";
speed: "fast" | "slow";
// 尚未定义的属性的索引签名
[key: string]: string;
}
declare const pick: HorseRace;
pick.breed;
pick.speed;
pick.ownerName;
在上面的示例中,我们定义了一个 HorseRac
e 接口,并为其赋予了一些属性,例如breed
、speed
和索引签名(用于未知属性)。当编译上面的代码时,将会提示以下错误:
error TS4111: Property 'ownerName' comes from an index signature, so it must be accessed with ['ownerName'].
要修改此错误,需要在调用属性 ownerName
时使用括号表示法:
pick.breed;
pick.speed;
pick["ownerName"]
默认情况下,Typescript 会忽略一个属性是否被设置为“undefined
”,因为它没有被定义,或者被定义为了 undefined
。
//exactOptionalPropertyTypes = false
interface Test {
property?: string;
}
const test1: Test = {};
console.log("property" in test1); //=> false
const test2: Test = { property: undefined };
console.log("property" in test2);
上面代码执行的时候不会产生错误,在 test1
中,检查是否定义了 property
;如果不是,它会打印一个 false
。在 test2 中,打印出 true
,因为定义了 property
并将其设置为 undefined
。接下来,把 exactOptionalPropertyTypes
选项设置为 true:
//exactOptionalPropertyTypes = true
interface Test {
property?: string;
}
const test1: Test = {};
console.log("property" in test1); // false
const test2: Test = { property: undefined };
console.log("property" in test2); // true
编译上述代码时,将会提示以下错误:
error TS2375: Type '{ property: undefined; }' is not assignable to type 'Test' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties. Types of property 'property' are incompatible. Type 'undefined' is not assignable to type 'string'.
这里,Typescript 不允许定义 undefined
的属性。为了解决这个问题,可以用 undefined 类型定义属性。
//exactOptionalPropertyTypes = true
interface Test {
property?: string | undefined;
}
const test1: Test = {};
console.log("property" in test1); //false
const test2: Test = { property: undefined };
console.log("property" in test2); //true
当启用 exactOptionalPropertyTypes
时,Typescript 会意识到这两种具有未定义属性的不同方式。它还确保如果我们想显式地将属性定义为 undefined
,则必须首先使用 undefined
类型对其进行注释。
当这个选项设置为 false
时,将遵循运行 Typescript 的操作系统 (OS) 的区分大小写规则。它可以区分大小写(操作系统区分文件名中的小写和大写字符)或不区分大小写(操作系统不区分字符大小写)。当 forceConsistentCasingInFileNames 选项设置为 true 时,如果尝试导入名称大小写与磁盘上文件名称大小写不同的文件,Typescript 将引发错误。
// StringValidator.ts
export interface StringValidator {
isAcceptable(s: string): boolean;
}
// ZipCodeValidator.ts
import { StringValidator } from "./stringValidator";
export const numberRegexp = /^[0-9]+$/;
export class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s);
}
}
在不考虑文件名大小写的情况下,在上面的代码中导入 StringValidator.ts
文件。如果 forceConsistentCasingInFileNames
选项设置为 true
,将会提示以下错误:
error TS1149: File name 'C:/Users/acer/Desktop/workBase/writing/Typescript/tsc/stringValidator.ts' differs from already included file name 'C:/Users/acer/Desktop/workBase/writing/Typescript/tsc/StringValidator.ts' only in casing.
要解决此问题,需要在导入文件时确保文件名大小写正确。
编译选项大致可以分为五类:基础选项、类型检查选项、额外检测选项、模块解析选项、Source Map 选项、实验选项。
ES3(默认值)
、ES5
、ES2015
、ES2016
、ES2017
、ESNEXT
。如果不配置 target
项,默认是将代码转译为 ES3
的版本,如果设为 ESNEXT
,则为最新 ES 规范版本。commonjs
、amd
、system
、umd
、es2015(或写 es6)
。如果不设置 module
选项,则如果 target
设为 ES6,那么 module
默认值为 ES6,否则为 commonjs
。lib
配置,默认会加载一些库,而加载什么库是受 target
影响的。如果 target
为 ES5,默认包含的库有DOM
、ES5
和ScriptHost
;如果 target
是 ES6,默认引入的库有DOM
、ES6
、DOM.Iterable
和ScriptHost
。false
,即不编译 JS 文件。preserve
’, ‘react-native
’,‘react
’,用于编译 jsx 代码React.createElement
。.d.ts
"声明文件。如果设为 true,编译每个 ts 文件之后会生成一个 js 文件和一个声明文件。但是 declaration
和 allowJs
不能同时设为 true。.d.ts
生成.map
文件.map
文件。"./dist/main.js"
,则输出的文件为一个 main.js
文件。但是要注意,只有设置 module
的值为 amd 和 system 模块时才支持这个配置。tslib
里的辅助工具函数,默认为 false。declaration
同时设定。/!*
开头的版权信息。noImplicitAny
设为 true,则如果没有设置明确的类型会报错。默认值为 false。use strict
",用来告诉浏览器该 JS 为严格模式。null
和 undefined
值不能赋值给非这两种类型的值,别的类型的值也不能赋给它们。除了 any 类型,还有个例外就是 undefined
可以赋值给 void
类型。strictFunctionTypes
,这个赋值就会报错。默认为 falsetrue
后会检查类的非 undefined
属性是否已经在构造函数里初始化,如果要开启该项,需要同时开启 strictNullChecks
,默认为 false。bind
、call
和 apply
绑定方法参数的检查是严格检查的。注意: 开启了这些检查如果有错会提示但不会报错。
node
和classic
两种类型。.map
文件里。//# sourceMappingURL=
然后接 base64 字符串的形式插入在 js 文件底部。.ts
文件的内容也包含到输出文件中。控制是否开启一些实验性质的语法。
参考:
- https://blog.openreplay.com/improving-code-quality-in-typescript-with-compiler-options
- https://blog.openreplay.com/improving-code-quality-in-typescript-with-compiler-options-part-2
本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/pxbQbvZP2IWMQzA7v8YV4w
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。