本文对TS背景进行简单的介绍,用精简的语言和案例阐述了TS的常用类型,是TS入门学习很好的一篇文章。本文主要参考 《ts入门教程》 一书和 《TS常见类型》一文并加入了一些自己的思考和实践及整理了一些比较基础的面试题。
void
和undefined
的区别unknow
与any
类型的区别never
类型有了解吗?TS最底层的类型是什么?带着问题开始本篇文章的阅读吧
TypeScript
是由微软开发的一款开源的编程语言。TypeScript
是 Javascript
的超级,遵循最新的 ES6+
规范。TypeScript
扩展了 JavaScript
的语法。Java
、C#
这样的面向对象语言可以让 JS
开发大型企业项目。Typescript
的推广,谷歌的 Angular2.x+
就是基于 Typescript
语法。Vue
、React
也可以集成 TypeScript
。有过一定TS经验的同学可以了解一下TS的设计理念,这有助于我们更好的学习和理解TypeScript。
npm install -g typescript
tsc --init
生成配置文件 tsconfig.json
tsc helloworld.ts
生成 helloworld.js
运行和断点调试 要安装 ts-node
npm install ts-node
npx ts-node helloword.ts
运行和调试
--> JavaScript调试终端
)Preferences
> Languages & Frameworks
> TypeScript配置如下点击菜单 任务-运行任务 点击 tsc:监视-tsconfig.json
然后就可以自动生成代码了
TypeScript
是 JavaScript
的超集,.js
文件可以直接重命名为 .ts
即可TypeScript
编译报错,也可以生成 JavaScript
文件TypeScript
写的,也可以编写单独的类型文件供 TypeScript
读取TypeScript
的类型定义文件Angular2
就是使用 TypeScript
编写的TypeScript
拥抱了 ES6
规范,也支持部分 ESNext
草案的规范任何事物都是有两面性的,我认为 TypeScript
的弊端在于:
Interfaces
)、泛型(Generics
)、类(Classes
)、枚举类型(Enums
)等前端工程师可能不是很熟悉的概念TypeScript
能够减少其维护成本TypeScript
,在使用时就能获得代码补全了,比如 Vue 3.0
TypeScript
,以通过安装社区维护的类型声明库 比如npm install --save-dev @types/react
JavaScript
运行时的特性。JavaScript
TypeScript
与标准同步发展boolean
、number
、string
、null
、undefined
、Symbol
、BigInt
void
any
unknow
never
any
类型ts// 不显式的定义类型,也能够自动做出类型推论
let age = 1 // let age: number
age = 'zhangsan' // 报错 不能将类型“string”分配给类型“number”。ts(2322)
// 声明未赋值 自动推断为any类型
let person; // let person: any
补充知识点:类型推论
TypeScript
会在没有明确的指定类型的时候推测出一个类型,这就是类型推论。
例如 let age = 1
会自动推断为 age: number
我们知道在 JS
中存在包装对象的概念。
当你使用原始类型(字符串、数字、boolean值)调用属性或方法是,JS
会创建一个临时的包装对象,使你能够访问课操作原始数据类型的属性和方法。这个过程称为自动包装。
在TS
中也存在包装对象
tsvar str = "Hello";
var strObject = new String(str); // 创建一个字符串包装对象
console.log(strObject.length); // 访问字符串的长度属性
console.log(str.length); // 访问字符串的长度属性
// 在TS中也存在包装对象
// 报错 Type 'Boolean' is not assignable to type 'boolean'.
let createdByNewBoolean: boolean = new Boolean(1);
void
的区别是 undefined
和null
是所有类型的子类型
undefined
类型的变量,可以赋值给其他类型的变量(未指定strictNullChecks
时)ts// 这样不会报错
let num: number = undefined;
let u: void;
let num2: number = u; // 不能将类型“void”分配给类型“number”。ts(2322)
注意:
tsconfig.json
指定了"strictNullChecks":true
, null
和 undefined
只能赋值给 any
、 unknown
和它们各自的类型, undefined
可以赋值给void
类型。
- JS中
void
是一个运算符,表示忽略表达式的返回值, 或者或返回值是undefined
- JS函数总是返回一些东西,没有返回值即返回
undefined
TS
中可以用void
表示没有任何返回值的函数, 它是undfined
的父类型void
类型undefined
和null
赋值给void
类型(未指定strictNullChecks
时)ts// 未定义返回值自动推断为 void 类型
function alertName() {
alert('My name is Tom');
}
var showAlert = alertName(); // var showAlert: void
// null 和 undefined 可以赋值给 void
let unusable: void = undefined;
那么TS既然有了 undefined
为什么还需要 void
呢?区别是什么?
区别在于 作为返回类型的void可以用不同的类型替换,以允许高级回调模式
tsfunction doSomething (callback: () => void) {
let c = callback(); // 此时c为void类型
// ...
}
// 返回number类型
function aNumberCallback (): number {
return 2;
}
doSomething(aNumberCallback);
TS新手超级喜欢这个类型
any
成了系统的顶级类型ts// 但如果是 any 类型,则允许被赋值为任意类型。
let myFavoriteNumber: any = 'seven';
myFavoriteNumber = 7;
// 在任意值上访问任何属性都是允许的:
console.log(myFavoriteNumber.logName);
// 也允许调用任何方法:
myFavoriteNumber.split('');
// 声明未赋值 推断为any
let any1; // any1: any
与 any
一样都是TypeScript的顶层类型,所有类型都可以分配给unknow
与 any
不同的是
unknow
类型执行任意操作,必须先缩小到具体类型才能使用其方法和属性unknow
类型只能被赋值给any
类型和unknow
类型本身缩小未知类型的范围的三种方法
typeof
is
关键字tslet unknownVal: unknown = 'str';
unknownVal = true; // 所以所有类型都可以分配给unknown
// unknow类型只能赋值给any类型和unknow类型
let anyVal: any;
anyVal = unknownVal
let num: number = 12;
num = unknownVal; // 不能将类型“unknown”分配给类型“number”。ts(2322)
/* 缩小未知类型的范围的三种方法 */
// 类型断言
function toFixed(value: unknown) {
return (value as number).toFixed(2);
}
// typeof 类型保护
function toFixed2(value: unknown) {
if(typeof value === 'number') {
return value.toFixed(2);
}
}
// is 自定义类型保护
const isNumber = (val: unknown): val is number => typeof val === 'number';
function toFixed3(value: unknown) {
if (isNumber(value)) {
return value.toFixed(2);
}
}
never
类型表示的是那些永不存在的值的类型,这意味着,定义了一个never
类型,只能被never
类型的值所赋值never
是 undefined
和null
的子类型, 是最底层的类型什么情况下会出现never
类型
let ne = (() => { while(true) {} })();
let ne2 = (() => { throw new Error("异常"); })();
tslet myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
function getLength(something: string | number): string {
console.log(something.length) // 不可以 number类型没有length属性
console.log(something.toFixed(2)) // 不可以, string类型没有toFixed方法
return something.toString();
}
在 TypeScript 中,我们使用接口(Interfaces)来定义对象的类型。
I
前缀。?
可选属性 readonly
只读属性[propName: string]: any;
tsinterface Person {
name: string;
age: number;
}
let tom: Person = { // 报错 缺少age属性
name: 'Tom'
};
let tom2: Person = { // 报错 不需要 gender 属性
name: 'Tom',
age: 25,
gender: 'male'
};
interface Person2 {
readonly name: string;
age?: number;
// [propName: string]: string; // 报错,任意类型必须包含可选类型和确定类型
[propName: string]: string | number | undefined;
}
let jack: Person2 = {
name: 'zs'
}
jack.name = 'ls' // 报错
jack.age = 12; // ok
jack.sex = 1 // ok
// 只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候
interface Person3 {
readonly id?: number;
name: string;
age?: number;
[propName: string]: any;
}
let tom3: Person3 = {
name: 'Tom',
gender: 'male'
};
tom3.id = 89757; // 报错
let fibonacci: number[] = [1, 1, 2, 3, 5];
let fibonacci: Array<number> = [1, 1, 2, 3, 5];
tsinterface NumberArray {
[index: number]: number;
}
let fibonacci: NumberArray = [1, 1, 2, 3, 5];
tsfunction sum() {
let args: number[] = arguments; // 报错
}
// Type 'IArguments' is missing the following properties from type 'number[]': pop, push, concat, join, and 24 more.
function sum() {
let args: IArguments = arguments;
}
// IArguments 是TS内置对象
// 实际 IArguments 定义如下
interface IArguments {
[index: number]: any;
length: number;
callee: Function;
}
// 用 any 表示数组中允许出现任意类型
let list: any[] = ['xcatliu', 25, { website: 'xcatliu.com' }];
?
readoly
修饰参数 只能在构造函数中使用ts// 函数声明语句
function sum(x: number, y: number): number {
return x + y;
}
sum(1); // 报错,不能少参数
sum(1, 2); // ok
// 函数定义表达式
let mySum = function (x: number, y: number): number {
return x + y;
};
// 等同于如下代码
let mySum: (x: number, y: number) => number = function (x: number, y: number): number {
return x + y;
};
// 使用interface修饰函数
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
return source.search(subString) !== -1;
}
// 函数重载
function reverse(x: number): number; // 重载签名
function reverse(x: string): string; // 重载签名
// 实现签名
function reverse(x: number | string): number | string | void {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}
数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象
ts// 元组的定义
let tom4: [string, number] = ['Tom', 25];
let tom5: [string, number];
// tom5 = [25, 'Tom'] // 报错
tom5 = ['Tom', 25]
tom5[0] = 'Tom'; // 可以只赋值其中一项:
// 当赋值或访问一个已知索引的元素时,会得到正确的类型:
tom4[0].slice(1);
tom4[1].toFixed(2);
// 当添加越界的元素时,它的类型会被限制为元组中每个类型的联合类型:
tom4.push('male'); // ok
tom4.push(true); // 报错
本文作者:郭敬文
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!