编辑代码

console.log("Hello  world!    - typescript.jsrun.net")

// TypeScript 基础学习

// 一、TS 和 JS 对比

// let temp:number[] = [1,2,3,4,5] //Error: 因为函数期望一个字符串类型的参数,但是传递了一个数字数组(即 number[])
let temp: string = "1, 2, 3"  //√
const fun = (temp: string) => temp.split(',')
console.log(fun(temp))

// 二、TS的基本数据类型

/* 
    基础语法:
        let 变量名: 类型 = 值;
    (给变量规定的是什么类型就是什么类型,不能随便写,否则就会报错)
 */
//①number ②string ③boolean ④undefined ⑤null  ⑥object
var a: number = 1;
let b: string = 'typescript';
// let b:string = false
const c: boolean = true;
const e: undefined = undefined;
const f: null = null;
let obj: object = { a: 'A', b: 'B' }

// const x: bigint = 123n;
let t: Symbol = Symbol()  //可以显示声明
let m = Symbol()   //直接创建

// any, unknown,never,void,array,tuple,enum

// 1、any:表示任意类型数据,就像写没有类型的原生 JS 一样,一般不推荐使用
let x: any = 8;
let x1: string = 'yun'
let x2: boolean = false

// 2、unknown:未知类型的值,类似 any,①实际上就是一个类型安全的严格版的any,避免了污染问题,从而克服了any类型的一大缺点。
let v: unknown = 123;
// let v1:boolean = v; // Error
// let v2:number = v; // Error

// ②另外不能直接调用unknown类型变量的方法和属性。
let unk1: unknown = { foo: 123 };
// unk1.foo  // Error

let unk12: unknown = 'hello';
// unk12.trim() // Error
(unk12 as string).trim()
console.log(unk12)

let unk123: unknown = (n = 0) => n + 1;
// unk123() // Error


// 3、never: 表示一个 无法被观测的类型,被赋予了该类型的变量什么都不能做。
let nTemp: never;
// nTemp = 1 // Error
// nTemp = 'hello' // Error:不可能赋给它任何值,否则都会报错

// 但是可以赋值给任意其他类型, 一般使用场景是一个无法走到 return 返回值的函数,比如:一定会抛出错误或死循环
function n2(): never {
    throw new Error('Error');
}
let nv1: number = n2(); //√
let nv12: string = n2(); //√
let nv13: boolean = n2(); //√

// 4、void:用于表示一个 函数没有返回值。
function getName(str: String): void {
    console.log('123');
    //     return 123; // Error
    return  //√
}

// 5、array
/* 
    两种写法:
        1、在元素类型后面加上[]: 类型[]
        2、使用数组泛型:Array<类型>
 */
// 在元素类型后面加上[]
let nrr: number[] = [1, 2, 3]        //nrr中的数据必须为number
let srr: string[] = ['a', 'b', 'c']  //srr中的数据必须为string
// let brr:boolean[]=[1,'a']       //Error:数组元素的类型与定义的不符 
// 或者使用数组泛型
let arrNew2: Array<number> = [1, 2, 3]
let brr2: Array<string> = ['a', 'b']

// 6、tuple:一种限制数组的元素类型和个数的数组

//定义为元组,则类型和数量都必须与之匹配
let arr: [string, number] = ['a', 2]  //√
// let brr:[string,number]=[2,'b']  //Error:不能将类型"string"分配给类型"number"
// let crr:[string,number]=['c',3,5] //Error:赋值了 3 个元素,但目标仅允许 2 个

//允许向元组中push元素,但push的新元素无法访问
arr.push(2)
console.log(arr);  //['a', 2, 2]
// console.log(arr[2]); //Error:长度为 "2" 的元组类型 "[string, number]" 在索引 "2" 处没有元素

// 7、enum: 枚举类型用于定义数值集合,默认情况下,从0开始为元素编号
enum num {
    one,
    two,
    three
};
let n: num = num.two
console.log(n);  //1


/* 三、TypeScript进阶特性 */

// 1、type:  定义类型别名对象, 目的 为解决给联合类型的类型定义过长的问题,而且还可以复用
// 示例1
type otherName = string | boolean
let bNew: otherName
console.log( bNew = '使用type关键字起别名')
// console.log( bNew =600) //Error:申明的类型为string

// 示例2
//不使用类型别名
function hander2(x: number, y: number, z?: number) {
}
//使用类型别名
type myx = { x: number, y: number, z?: number }
function hander3(mytype: myx) {
}

// 2、interface: 相比较类型别名type,少了=, 且可以多次声明,支持继承
//示例1:接口interface,没有=号
interface myX2 {
    x: number
    y: number
    z?: number
}
//interface可以多次申明
interface myX2 {
    z?: number
}
//使用接口interface声明
function hander4(mytype: myX2) { }

//示例2:interface支持继承
interface myIn8 {
    x: number
    y: number
}
interface myIn3 extends myIn8 {
    m?: number
}
function hander5(mytype: myIn3) {
    console.log(mytype.x, mytype.y, mytype.m)
}
hander5({ x: 1, y: 2, m: 7 })

// 3、&: 交叉类型
type Teacher = { name: string }
type Person = { age: number }
type teacherPerson = Teacher & Person
let all: teacherPerson = { name: '小明', age: 18 }
console.log(all)

// 4、| : 联合类型
function getString(something: string | number): string {
    return something.toString();
}
console.log(getString('这是字符串'))
console.log(getString(678))

// 5、as: 断言,允许你将某个值强制转换为你期望的类型,  unknown :unk12中使用过
let someValue: any = function () { /* ... */ };
let func = someValue as Function;

let someValue2: any = 42;
let num2 = someValue2 as number;


// 6、泛型: <T>
function combine<T>(arr1: T[], arr2: T[]): T[] {
    return arr1.concat(arr2)
}
//两个参数不同的类型,使用联合类型,此时不能省略类型参数的值
let tempT = combine<number | string>([1, 2], ['a', 'b'])
console.log(tempT) // [1, 2, "a", "b"] 

// 7、keyof
type Dog = { name: string; age: number; };
type D = keyof Dog;
//type Dog = {
//     name: string;
//     age: number;
// }

// 8、extends
type BaseType = string | number  // | boolean
function copy<T extends BaseType>(arg: T): T {
    return arg
}
//对泛型进行约束,传入的参数必须BaseType这些型
copy(1) //ok
// copy(false)  //Error

// 9、in
type ReadonlyFor<T> = {
    readonly [P in keyof T]: T[P]
    // 1、keyof T:用于得到联合类型'a'|'b'
    // 2、P in keyof T= P in 'a'|'b',相当于执行一次forEach,遍历'a'|'b'
};
interface Obj {
    a: string;
    b: string;
}
type ReadonlyObj = ReadonlyFor<Obj>
let mr: ReadonlyObj = { a: 'a', b: 'b' }
// mr.a = '99' //Error:Cannot assign to 'a' because it is a read-only property.
console.log(mr) // {"a": "a", "b": "b"}

// 10、条件类型:T extends U ? X : Y  即当被检查类型(类型 T)可以赋值给类型 U时,返回类型 X,否则返回类型Y 
type IsString<T> = T extends string ? true : false;
type I1 = IsString<"abc">;  // true
type I31 = IsString<321>;  // true