1. 安装
- 下载vcode
按ctrl+k ctrl+l,然后搜索格式化文件,设置格式化的快捷键 -
npm install [email protected] -g
npm install [email protected] -g
记下ts-node可执行文件路径 - 配置文件(.vscode/launch.json)
{
"configurations": [
{
"name": "ts-node",
"type": "node",
"request": "launch",
"program": "这里写之前ts-node的安装路径",
"args": ["${relativeFile}"],
"cwd": "${workspaceRoot}",
"protocol": "inspector"
}
]
}
2. ts文档
1. 第一步
创建greeter.ts文件,按下保存的快捷键,再命令行进入当前文件夹运行tsc greeter.ts
,这样就转成js文件
function greeter(person: string) {
return "Hello, " + person;
}
let user = "Jane User";
console.log(greeter(user));
// 若传的不是string会报错,但undefined可以通过
2. 接口
interface可以让你规定一个对象必须要有哪些属性,同时在函数传的参数里也只能用这些属性
interface Person {
firstName: string;
lastName: string;
}
function greeter(person: Person) {
return "Hello, " + person.firstName + " " + person.lastName;
}
let user = { firstName: "Jane", lastName: "User" };
console.log(greeter(user));
3. 类
类可以支持函数
class Student {
fullName: string;
firstName: string;
constructor(firstName: string, public middleInitial: string, public lastName: string) {
this.firstName = firstName
this.fullName = firstName + " " + middleInitial + " " + lastName;
}
}
interface Person {
firstName: string;
lastName: string;
}
function greeter(person : Person) {
return "Hello, " + person.firstName + " " + person.lastName;
}
let user = new Student("Jane", "M.", "User");
console.log(greeter(user));
public等于帮你申明一个变量并在constructor里写上this.lastName = lastName
,所以Student有四个属性:fullName、firstName、middleInitial、lastName,但在函数greeter里只能用接口里有的属性,不能用fullName,除非你接口用Student
3. 实现一些简单函数
1. 找较小数
function min(a: number,b: number): number{
if(a>b){
return b
}else{
return a
}
}
console.log(min(2,1))
意思是返回值也必须是number
2. 重载
function add(a: string, b: string): string;
function add(a: number, b: number): number;
function add(a: any, b: any): any {
return a+b
}
console.log(add('a','d'));
a和b只支持同时是string或者同时是number类型
3. 定义数组的方式
- 第一种
let a: number[] = [1,2,3]; // 意思是由number组成的数组
- 第二种
let b: Array = [1,2,3]
3. 元祖
已知元素数量和类型情况下的数组可以用元祖
let x: [string, number];
// Initialize it
x = ['hello', 10]; // OK
// Initialize it incorrectly
x = [10, 'hello']; // Error
3. 判断是否能结婚
interface human{
gender: string;
}
function merry(a: human,b :human): [human, human]{
if(a.gender !== b.gender){
return [a,b]
} else{
throw new Error('性别相同不能结婚')
}
}
let a = {gender: 'male'}
let b = {gender: 'female'}
console.log(merry(b,b));
- 枚举
给性别规定只能是male和female
enum Gender {
Male,
Female
}
interface human{
gender: Gender;
}
function merry(a: human,b :human): [human, human]{
if(a.gender !== b.gender){
return [a,b]
} else{
throw new Error('性别相同不能结婚')
}
}
let a = {gender: Gender.Male}
let b = {gender: Gender.Female}
console.log(merry(a,b));
4. 实现一些命令行工具
1. process.argv
在1.ts文件里写
#!/usr/bin/env ts-node // 蛇棒
console.log(process.argv)
// 在命令行里运行`./1.ts abc`,process.argv 就是这一行的内容
console.log(123);
第一行加了蛇棒,在命令行运行node ./1.ts
的时候就不用加node,直接运行./1.ts
即可
运行npm init -y
,在目录里添加package.json文件
运行npm i -D @types/node
,安装process的包
2. 加法
给ts加es6的语法库,在目录下创建tsconfig.json文件,去网上复制tsconfig.json的默认格式,然后在里面添加"es2015"
// tsconfig.json
{
"compilerOptions": {
"lib": [
"es2015"
]
}
}
- add.ts
#!/usr/bin/env ts-node
let a: number = parseInt(process.argv[2])
let b: number = parseInt(process.argv[3])
if(Number.isNaN(a) || Number.isNaN(b)){
console.log('必须是数字')
} else {
console.log(a+b)
}
命令行运行./add.ts 1 2
#!/usr/bin/env ts-node
{
let a: number = parseInt(process.argv[2])
let b: number = parseInt(process.argv[3])
if(Number.isNaN(a) || Number.isNaN(b)){
console.log('必须是数字')
process.exit(1)
}
console.log(a+b)
process.exit(0)
}
成功的退出返回0,不成功的返回1
3. 族谱
#!/usr/bin/env ts-node
{
class Person{
public Children: Person[] = [];
constructor(public name: string){}
addChild(child: Person): void {
this.Children.push(child)
}
introduceFamily(n: number): void {
let pre = '----'.repeat(n-1)
console.log(pre + this.name)
this.Children.forEach(child=>{
child.introduceFamily(n+1)
})
}
}
let a = new Person('jpj')
let b = new Person('son')
let c = new Person('daughter')
a.addChild(b)
a.addChild(c)
a.introduceFamily(1)
}
下面将n改为可选参数
#!/usr/bin/env ts-node
{
function createPre(n: number): string {
return '----'.repeat(n)
}
class Person{
public Children: Person[] = [];
constructor(public name: string){}
addChild(child: Person): void {
this.Children.push(child)
}
introduceFamily(n?: number): void {
n = n || 1
console.log(createPre(n-1) + this.name)
this.Children.forEach(child=>{
child.introduceFamily(n+1)
})
}
}
let a = new Person('jpj')
let b = new Person('son')
let c = new Person('daughter')
a.addChild(b)
a.addChild(c)
a.introduceFamily(1)
}
在n后加个?,就变为可选参数
5. 模版字符串
let name: string = `Gene`;
let age: number = 37;
let sentence: string = `Hello, my name is ${ name }.
6. 枚举
enum Color {Red, Green, Blue}
let c: Color = Color.Green;
enum Color {Red = 0, Green, Blue}
let colorName: string = Color[2];
console.log(colorName); // 显示'Blue'
7. any
// 前面不加any,这样用编译时就会报错
let notSure = 412312;
console.log(notSure.substr())
// 加个any就会在执行时报错
let notSure: any = 412312;
console.log(notSure.substr())
// 在不知道数组类型时也可以用any
let list: any[] = [1, true, "free"];
list[1] = 100;
8. void
// void表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是 `void`:
function warnUser(): void {
alert("This is my warning message");
}
// 声明一个void类型的变量没有什么大用,因为你只能为它赋予undefined和null:
let unusable: void = undefined;
9. 可选属性
加了?疑问号之后,就变为可选属性,如果不加疑问号的话在写createSquare的参数的时候就必须同时传color和width
interface SquareConfig {
color?: string;
width?: number;
}
function createSquare(config: SquareConfig): {color: string; area: number} {
let newSquare = {color: "white", area: 100};
if (config.color) {
newSquare.color = config.color;
}
if (config.width) {
newSquare.area = config.width * config.width;
}
return newSquare;
}
let mySquare = createSquare({color: "black"});
10. 接口
1. 只读属性
interface Point {
readonly x: number;
readonly y: number;
}
let p1: Point = { x: 10, y: 20 };
p1.x = 5; // error!
// 赋值
- 还有只读的数组
let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray = a;
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!
赋新值也不行,除非用类型断言重写
a = ro as number[];
做为变量使用的话用 const,若做为属性则使用readonly。
2. 额外的属性检查
如果你能够确定这个对象可能具有某些做为特殊用途使用的额外属性
interface SquareConfig {
color?: string;
width?: number;
[propName: string]: any;
}
3. 接口也可以定义函数
interface SearchFunc {
(source: string, subString: string): boolean;
}
// 函数的参数名不需要与接口里定义的名字相匹配
let mySearch: SearchFunc = function(src: string, sub: string): boolean {
let result = src.search(sub);
return result > -1;
}
11. 函数
let myAdd: (baseValue: number, increment: number) => number =
function(x: number, y: number): number { return x + y;
};
函数也不会固定参数的名字,只要类型匹配就可以
- 剩余参数
在你不确定参数个数时
function buildName(firstName: string, ...restOfName: string[]) {
return firstName + " " + restOfName.join(" ");
}
let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
console.log(employeeName);
12. 泛型
一个函数想让传入参数类型和return类型相同时,可以用泛型
function identity(arg: T): T {
console.log(T.length) // 报错
return arg;
}
这样你传的是什么类型,输出就必须是什么类型
function loggingIdentity(arg: T[]): T[] {
console.log(arg.length); // 这样就不会报错
return arg;
}
13. 声明合并
1. 合并接口
interface Box {
height: number;
width: number;
}
interface Box {
scale: number;
}
let box: Box = {height: 5, width: 6, scale: 10};
13. 类型兼容性
1. 函数
let x = (a: number) => 0;
let y = (b: number, s: string) => 0;
y = x; // OK,可以把x赋给y
x = y; // Error,不能把y赋给x
console.log(x(123123))