1. 最近有时间学习了一下typescript,那么typescript跟js有什么区别呢?
js:
- js易学易用,用来开发项目开发速度还是很快的,但是后期不易维护;
- 声明变量为动态类型,假如代码某一块因为数据类型报错不易调试找出bug;
- js定义一个函数,传的参数也没有类型和个数的限制。
typescript是什么?
- 以javascript为基础构建的语言,是javascript的超集。
- ts完全支持js,在js的基础上,引入了类型的定义。
- 可以在任何支持js的平台执行,但是ts不能被js解析器直接执行。
.ts文件不能在浏览器中直接执行,需要进行编译为js文件,执行的最终还是js文件。
2. 怎么来编译ts文件为js文件?
(1)需要npm全局安装typescript
npm install typescript -g
(2)检测是否安装完毕,在控制行中输入:tsc 如果出现以下内容,说明安装成功。
(3) 进入到项目目录,执行 tsc 文件名称,执行完成会在项目目录下面新增一个js文件。
3. ts在js的基础上面新增了哪些功能?
- 类型检测
- 支持es新特性
- 添加了es不具备的新特性(装饰器,接口等等)
- 丰富的配置选项(严格或者不严格可以自行配置)
- 强大的开发工具
- ts有错误依然可以编译成功,为了降低出错的情况,可以通过配置实现有错误就编译不成功。
ts可以编译任意版本的js,默认编译为es3的版本js,这个可以通过配置实现。
4. ts有哪些作用?
增加了类型检测:
可以给一个变量进行类型定义
可以给函数参数以及返回值进行变量类型声明以及参数的个数进行检测
5. webpack怎么打包ts?
(1) 新建文件夹,npm init -y生成package.json文件,tsc --init 生成ts配置文件
(2) 下载依赖:
npm install -D webpack@4.41.5 webpack-cli@3.3.10 webpack-dev-server@3.10.2 html-webpack-plugin clean-webpack-plugin ts-loader cross-env
(3) 新建webpack.config.js文件进行webpack配置
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const isProd = process.env.NODE_ENV === 'production' // 是否生产环境
function resolve (dir) {
return path.resolve(__dirname, '..', dir);
}
module.exports = {
mode: isProd ? 'production' : 'development',
entry: {
app: './src/main.ts'
},
output: {
filename: '[name].[contenthash:8].ts',
path: resolve('dist')
},
module: {
rules: [{
test: /\.tsx?$/,
use: 'ts-loader',
include: [resolve('src')]
}]
},
plugins: [
new CleanWebpackPlugin({}),
// 针对当前public目录下的index.html进行打包
new HtmlWebpackPlugin({
template: './public/index.html'
})
],
resolve: {
extensions: ['.ts', '.tsx', '.js']
},
devtool: isProd ? 'cheap-module-source-map' : 'cheap-module-eval-source-map',
devServer: {
host: 'localhost',
stats: 'errors-only',
port: 8080,
open: true
}
}
(4) 配置打包命令
"dev": "cross-env NODE_ENV=development webpack-dev-server --config build/webpack.config.js",
"build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"
(5) 运行与打包
npm run build
npm run dev
6. ts有哪些基本类型,怎么使用呢?
-
undefined && null
都可以作为其他类型的子类型,赋值给其他类型的变量的。(但是会报错是因为tsconfig.json中开启了严格模式)
let und: undefined = undefined;
let nul: null = null;
console.log(und, nul); // undefined null
let num5: number = undefined;
console.log(num5) // undefined
-
number
表明声明一个变量a,并且类型设置为number
let a: number;
a = 123;
// a = 'hello'; // 此行代码会报错,类型错误,只能为number
如果变量声明和赋值同时进行,ts会自动的对变量进行类型检测,以后在运用c的时候只能赋值为number类型。
let c = 123;
c = 456;
// c = 'hello'; // 会报错,只能为number类型
js中的函数是不考虑参数的类型和个数的,但是ts是考虑的,只要个数还有参数类型不一样,就会提示警告。最后一个number表示函数返回值类型为number
function sum(a: number, b: number): number {
return a + b;
}
console.log(sum(123, 456));
console.log(sum(123, 456, 789)); // 会报错,因为参数个数只能为两个
-
string
let b: string;
b = 'hello';
-
boolean
let c: boolean;
b = true;
b = false;
-
字面量
假如声明一个变量类型为一个常量,则相当于声明了一个常量,并且值不能再次修改,否则会报错。
let a1: 10;
// a1 = 11; // 报错,只能是10,不能修改
-
any
表示任意类型,设置为any后相当于对该变量关闭了ts的类型检测,不建议使用any
let d1: any;
d1 = 10;
d1 = 'hello';
// 声明变量如果不指定类型,则ts解析器会自动的判断变量类型为any (隐式的any)
let d2;
// 当一个数组中存储多个数据,个数不确定,类型不确定,此时可以使用any类型来定义数组
let arr6: any[] = [100, 'hello', true];
// 数字类型没有split方法,在控制台下面会报错,但是这种情况也没有错误的提示信息也没有编译失败,所以说any类型有优点,也有缺点。
console.log(arr6[0].split('')); // Error
-
unknown
类型安全的any,表示未知类型的值,实际上就是一个类型安全的any,不能直接赋值给其他变量
let a: any;
let b: unknown;
let c: string;
// c为字符串,当把一个any类型的值a赋值给c,也没有报错,any类型的变量可以赋值给任意变量。
c = a;
// b的变量类型是未知的,将未知类型的变量赋值给别的类型时,会报错,unknown只会祸祸自己。
c = b;
// 这个时候可以加个类型判断也是可以的
if (typeof e === 'string') {
s1 = e;
}
-
联合类型 & 类型断言 & 类型推断: 表示取值可以为多种类型中的一种
类型断言:可以用来告诉解析器变量的实际类型 (通过类型断言这种方式告诉编译器: 我知道我自己是什么类型,也知道自己干什么)
类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。 它没有运行时的影响,只是在编译阶段起作用。 TypeScript会假设你,程序员,已经进行了必须的检查。
语法:(两种用法)
变量 as 类型
<类型>变量
类型推断:ts会在没有明确指定类型的时候推测出一个类型
有以下两种情况:
定义变量时赋值,推断为对应的类型
定义变量时没有赋值,推断为any类型
联合类型:可以使用 | 来连接多个类型,表示变量类型满足于声明的任一个都可以。
let c1: string | boolean;
// 总之类型不确定的变量能用unknown就用unknown,能尽量不用any就不用any
s1 = e as string;
s1 = <string>e;
let b1: 'male' | 'fmale';
b1 = 'male';
let c1: string | boolean;
c1 = 'hello';
c1 = false;
-
void
与any相反,多用在函数声明的时候,小括号后面使用:void,表示该函数没有任何返回值(返回值为null/undefined)
没有值或者undefined 空值、undefined,常用来设置函数的返回值,如果不设置,自动归为any
function fn1(num) {
if (num > 0) {
return true;
} else {
return 123;
}
}
function fn2(): boolean {
return true;
}
function fn3(): string {
return '123';
}
function fn4(): string | boolean {
return 'hello';
}
// void表示空,表示函数没有返回值
function fn5(): void {
return;
}
-
never
不能是任何值 没有值,表示永远不会返回结果,在js中有一种函数报错不需要返回结果,相对用的较少
function fn6(): never {
throw new Error('报错了!')
}
-
object
object 表示一个js对象,(数组,function都是一个对象),相对用的较少,一般用的是{}
let a3: object;
a3 = {};
a3 = function () { }
a3 = [1, 2, 3]
{} 用来指定对象中可以包含哪些属性,声明赋值的变量值必须跟声明的里面结构类型一样
语法:
{属性名: 属性类型, 属性名: 属性类型}
// 属性名后面加一个?表示这个属性是可选属性
let b3: { name: string, age?: number };
b3 = { name: 'sunny', age: 18 };
b3 = { name: 'sunny' };
// [propName: string]表示任意字符串的属性名(propName是自定义的),any表示任意类型的属性值
let c3: { name: string, [propName: string]: any};
c3 = { name: 'joyn', age: '22' }
设置函数结构的类型声明
语法:
(形参: 类型, 形参: 类型 ...) =>返回值类型
// 声明d3为函数类型(隐式的类型声明):有两个参数都是number类型,并且返回值也是number类型
let d3: (a: number, b: number) => number
d3 = function(n1, n2) {
return n1 + n2;
}
-
array
array 一般用来存储相同类型的数组
类型声明,两种方式:
方式一: let 变量名: 数据类型[] = [值1, 值2, 值3]
方式二: 泛型方式: let 变量名: Array<数据类型> = [值1, 值2, 值3]
数组定义后,里面的数据类型必须和定义的数据类型一致,否则有错误提示信息,也不会编译通过。
例如: number[] / Array<number> 数值数组
string[] / Array<string> 字符串数组
any[] / Array<any> 含有多种类型的数组
// 表示e3为一个数组,并且里面元素类型都为字符串
let e3: string[];
let f3: Array<string>;
-
tuple(元组)
ts新增类型,固定长度的数组 (在定义数组的时候元素类型和数组的长度一开始就已经设定好了)
简单的来说就是类型固定,数组长度固定。数组中的每一个元素都要和类型一一对应,否则会报错。
如果调用数组中越界的一个元素,则该元素的类型可以是元祖定义类型中的任一种。
let g3: [string, number];
g3 = ['123', 123];
g3[3] = 'string'; g3[3] = 123; // 都不会报错,只要类型为string或者number中的一种都可以
g3[3] = true; // 会报错
-
enum
枚举,ts新增类型 enum(A, B),把所有可能的情况都给列出来,值需要在多个值之间选择,这个时候就会遇到枚举
枚举里面的每个数据值都可以叫元素,每个元素都有自己的编号,编号是从0开始的,依次递增1(也可以手动指定成员的数值)
enum Color {
red,
green,
blue
}
// 定义一个Color的枚举类型的变量来接收枚举的值。
let color: Color = Color.red;
console.log(color); // 0
console.log('red=', Color.red, 'green=', Color.green, 'blue=', Color.blue); // red= 0 green= 1 blue= 2
console.log('color=', Color[2]) // blue
let h3: { name: string, gender: 0 | 1 };
h3 = {
name: 'Sunny',
gender: 0
}
console.log(h3.gender === 0)
// 定义一个枚举类
enum Gender {
male,
fmale
};
let i3: { name: string, gender: Gender };
i3 = {
name: 'Sunny',
gender: Gender.male
}
console.log(i3.gender === Gender.male)
// &表示同时满足
let j3: string & number;
let k3: { name: string } & { age: number };
k3 = { name: 'sunny', age: 18 }
// 小例子:枚举中的元素可以是中文的数据值,但是不推荐
enum Gender {
女,
男
}
console.log(Gender[1]) // 男
类型的别名 简化类型的使用
// 这样定义变量类型很麻烦
let a: 1 | 2 | 3 | 4 | 5;
let b: 1 | 2 | 3 | 4 | 5;
// 定义类型别名
type myType = 1 | 2 | 3 | 4 | 5;
let a: myType;
let b: myType;
ts工具类型Partial
我们先来看一下partial的定义
Partial 可以快速把某个接口类型中定义的属性变成可选的(Optional)
// Make all properties in T optional
type Partial<T> = {
[P in keyof T]?: T[P];
};
假设我们有一个user接口
interface IUser = {
name: string
age: number
depart: string
}
const user1: IUser = {
name: 'sunny',
age: 18,
depart: '部门1'
}
const user2: IUser = {
name: 'sunny',
age: 18
} // 会报错,缺少一个depart属性
// 如果这个时候我们用partial类型转化一下呢??
type IUser1 = Partial<IUser>;
const user2: IUser1 = {
name: 'sunny',
age: 18
} // 不会报错了
// 因为Partial转化后IUser1相当于
interface IUser1 = {
name?: string | undefined
age?: number | undefined
depart?: string | undefined
}
ts刚接手可能会有点不习惯,我自己感觉是很麻烦,不过用的多了也就习惯了,对于变量的类型有严格的检测,对于项目后期的维护是很有帮助的。