// ts 会根据等号右边的内容推到他自身的类型,没有类型就是any , 在ts中:后面跟着的都是类型
// any会导致类型检测失效,能不写any 就不要写any**
// 1.ts中的基础类型 如果用大写的类型 String /Number / Boolean 类, 类也可以充当类型 类类型
// 大写的类型用来描述实例的
// 字符串 数字 number
let str: string = "zf";
let age: number = 100;
let bool: boolean = true;
let str0: string = "zf";
let str1: String = "zf"; // 字符串也是String的一个实例,调用方法的时候会进行装箱
// 把简单类型转换成引用类型 是装箱 'zf' -> new String('zf')
// let str2: String = new String("xxx");
// let str3: string = new String("xxx"); // 我们将一个对象标识成了基本数据类型
// export {}; // 导出后这个变量就属于模块内了,不会被声明在全局上 不会污染全局ts声名
let arr: (string | number)[] = [];
arr.push(100);
let item = arr[0];
(item as string).length 因为不确定是不是字符串或者数字
let arr1: Array<number | string> = [];
let tuple: [string, number, boolean] = ["zf", 13, true];
tuple.push(123);
即使可以这样操作,
// 4. 默认枚举类型会被编译成对象
// 源码里面表示不同状况的参数
enum AUTH { // 状态码,请求路径 常量 , 可以放置混合类型,但是只有数字后面才能递增
ADMIN,
MANGAER = 3,
USER,
// ADMIN = 'admin',
// MANGAER = 'manager',
// USER = 'user'
}
console.log(AUTH.ADMIN)
// 常量枚举 最终编译后的结果会变成具体的结果, 只要不是数组都不能反举。
AUTH.ADMIN默认是等于0,同样反举的话AUTH[0] = 'ADMIN'
console.log(Object.keys(AUTH).length)
let un: undefined = undefined;
let nu: null = null;
function sum(): void {
return undefined;
}
function whileTrue(): never {
while (true) {}
}
function throwError(): never {
throw new Error();
}
function isType(str: string) {
if (typeof str === "string") {
} else {
str;
}
}
function create(o:object){
}
create({})
create([])
create(function(){})
export {};加一个export表示是一个单独的模块 是不会影响到全局的ts声名,如果不加这个的话和全局的某个ts声名会冲突
let ele: HTMLElement | null = document.getElementById("app"); // 我是知道这个东西使用的
// ! 标识的是非空断言 ts里面的
// ele!.style.background = 'red'; // 这个东西一定不为空, 如果为空那就得自己承担错误,不用ts来检验了
// 断言 类型断言 只能断言已经存在的值
(ele as HTMLElement).style.background = "red"; // 断言后后果自理 ,不要ts的类型校验了
(<HTMLElement>ele).style.background = "red"; // 在使用jsx的时候还是使用as语法
// 考虑采用type关键字来自定义类型
// type是ts中用的时候 多数会配合联合类型来使用
type MyType1 = string | number | boolean | object;
type MyType2 = 'a' | 'b' | 'c' | 'd'; // 表示myType2 只能赋值成a,b,cd 中的4个
let n: MyType2 = 'b'; // 联合类型会根据赋值的值推导出具体的类型
// 不建议使用双重断言,会改变原有类型, 但是好处是可以断言成任何类型
// (ele as any as string).style.background = 'red'; // 断言后后果自理 ,不要ts的类型校验了
// -------------------
// js 本身语法
// ele?.style; // 类似于判断 如果有才能取值没有就直接返回了 如果需要转义低级语法 需要babel
// ?? js预算福
// console.log(null ?? 1); // 只要不是null或者undefined这个值就是ok的 解决的是||的问题,即使是false??1,返回的还是false
type MySum = (a: number, b: number) => number;
let sum: MySum = (x, y) => x + y;
function optionalArguments(x: string, y?: string, z?: string) {}
optionalArguments("a");
function defaultArguments(x: string = "", y: string) {
}
defaultArguments(undefined, "123");
function spreadAruments(...args: number[]) {
}
spreadAruments(1, 2, 3, 4);
interface fn {
shiyan: () => void;
shiyan1():void
}
function toArray(value: string): string[];
function toArray(value: number): number[];
function toArray(value: string | number) {
if (typeof value === "string") {
return value.split("");
} else {
return value.toString().split("").map(Number);
}
}
let r1 = toArray("abc");
let r2 = toArray(123);
export {};
class Pointer {
constructor(public readonly x: number = 1, public y: number) {
this.x = x;
}
get c() {
return 1000;
}
}
let p = new Pointer(1, 2);
console.log(p.x);
protected(受保护的) 表示实例无法访问,但是子类可以访问
private(私有的) 表示实例,子类无法访问
readonly 表示无法修改的
interface IFruit {
readonly taste: string;
color: string;
size?: number;
[xxx:string]:any 任意属性
}
let tomato: IFruit = {
taste: "甜的",
color: "黄色",
a: 1,
} as IFruit;
interface ISpeakChinese {
speakChinese: () => void;
}
interface ISpeakEnglish {
speakEnglish: () => void;
}
class Speak implements ISpeakChinese,ISpeakEnglish {
speakChinese(){
return ;
}
speakEnglish(){
return 'abc'
}
}
abstract class Animal {
abstract eat(): void;
abstract name: string;
drink() {
console.log("dirnk");
}
}
class Cat extends Animal {
name: string = "";
eat() {}
}
interface IArray1<T> {
[key:number]:T
}
type IArray<T> = {
[key:number]:T
}
let arr1:IArray<number> = [1,2,3];
let arr2:Array<string> = ['1','2'];
class Cat {
constructor(name: string, age: number) {}
}
class Dog {
constructor(name: string, age: number) {}
}
function createAnimal<T>(clazz: typeof Cat, name: string, age: number) {
return new clazz(name, age);
}
type MyClazz<T> = new (name: string, age: number) => T;
function createAnimal<T>(clazz: MyClazz<T>, name: string, age: number) {
return new clazz(name, age);
}
r显示的类型怎么都是对的
let r = createAnimal(Dog, "Tom", 12);
// ts中的类型标准并不会让代码执行, 静态检测
type ICreateArray = <T>(times:number,val:T)=>T[]
或者
interface ICreateArray {
// 写在接口后面表示使用接口的时候确定类型
<T>(times: number, val: T): T[]
}
这个T的类型是ts推导出来的
const createArray: ICreateArray = (times, val) => {
let result = []
for (let i = 0
result.push(val)
}
return result
}
let arr = createArray(3, "a")
//这个泛型是推导出来的
function swap<T, K>(tuple: [T, K]): [K, T] {
// 声明多个参数来使用
return [tuple[1], tuple[0]]
}
let r1 = swap(["a", 1])
泛型与泛型之间是不能相加的,即使直接传值也不行,为什么因为 ts中的类型标准并不会让代码执行, 静态检测,静态检测并不值到T和K 属于什么类型所以相加会报错,解决方案看下面的extends
let r1 = swap<string,number>(["a", 1])
interface ICb<T> {
(item: T, key: number): void;
}
interface IForEach {
<T>(arr: T[], cb: ICb<T>): void;
}
let forEach: IForEach = (arr, cb) => {
for (let i = 0; i < arr.length; i++) {
cb(arr[i], i);
}
};
forEach([1, 2, 3, 4, 5, "string"], (item) => {});
注意看下这个地方,这里还传了string类型,所以T就是(string | number)
function sum<T extends number|string>(a: T, b: T) {
return a as string +b;
}
let rr1= sum(1,2);
为什么说不一定和extends后面限制全部一样请看
function getFish<T extends {kind:string}>(fish:T){}
getFish({a:1,kind:'鲨鱼'});
type MyType = keyof number MyType就是数字类型上面的方法
type MyAny = keyof any;
function map<K extends keyof any,V,U>(obj:Record<K,V>,fn:(value:V,key:K)=>U ):Record<K,U>{
let result = {} as Record<K,U>;
for(let key in obj){
result[key] = fn(obj[key],key)
}
return result
}
let returnValue = map({a:'a',b:'b'},(value,key)=>{
return value+'a'
});
如何合并ts两个接口,下面覆盖上面的
interface IPerson1 {
name: string;
}
interface IPerson2 {
name: number;
age: string;
}
type Diff<T, K> = Omit<T, keyof K>;
type Merge<T, K> = Diff<T, K> & K;
// 自定义的类型 全局没有
namespace fn {
function extend(): void;
}
}
declare function $(): {
html(): void;
css(key: string, value: string): void;
}; // declare 告诉ts 你可以声明这个变量 但是并不需要初始化
declare global {
// 给ts中已经声明过的类型进行扩展
interface Window {
a: string;
}
interface Number {
myFixed(): void;
}
}
// "moduleResolution": "node", 是干嘛的,我调用import语法 文件应该怎么样去解析文件
// "baseUrl": "./", 是表示怎么查找路径的 ./在当前目录下查找
// "paths": {"*":[ 我们引入文件 指定文件去哪里找
// "types/"
// ]},
// 一般是在import a from 'a.vue'
declare module '*.vue' { // 用户引入vue默认引入后拿到的就是a这个变量
export let a:string
}
declare module '*.gif'
export {} //这个如果没写 就表示是模块内部的
关于ts为什么用类,可以简化很多操作, 尤其深层次嵌套, 可以不用问号 还可以初始化值
class Person {
name:string = '';
age:number = 1;
}
class P {
person: Person = new Person();
}
interface IState {
test: P;
}
class Button extends React.Component<any, IState> {
state = {
test: new P(),
};
render() {
const { test } = this.state;
return <div>{test.person.name}</div>;
}
}
interface X {
(): void;
}
type MyReturnType = ReturnType<typeof sum>;
type Parameters<F extends (...args: any[]) => any> = F extends (
...args: infer R
) => any
? R
: any;
type MyParameters = Parameters<typeof sum>;
class Animal {
constructor(a: string, b: string, c: number) {}
}
type ConstructorParameters<C extends new (...args: any[]) => any> =
C extends new (...args: infer R) => any ? R : any;
type MyConstrcutorParams = ConstructorParameters<typeof Animal>;
type InstanceType<C extends new (...args: any[]) => any> = C extends new (
...args: any[]
) => infer R
? R
: any;
type MyinstanceType = InstanceType<typeof Animal>;
let a: unknown = 1;
type r1 = unknown | string;
type r2 = unknown & string;
type r3 = keyof unknown;
class Person {}
class Animal {}
function getType(type: Person | Animal) {
if (type instanceof Person) {
type;
} else {
type;
}
}
let person1 = {
name: "jw",
high: true,
};
let person2 = {
name: "zf",
fat: true,
};
type Zhu = typeof person2;
type Jw = typeof person1;
function getPerson(person:Zhu | Jw){
if('high' in person){
person
}else{
person
}
}
interface I1 {
name: "jw",
high:string
}
interface I2 {
name: "zf",
fat:string
}
function isJw(person:I1 | I2):person is I1{
return person.name === 'jw'
}
function getPerson2(person:I1 | I2){
if(isJw(person)){
person
}else{
person
}
}
"strictFunctionTypes": false, 决定着是否开启双向协变
let a1!: string | number;
let a2!: string | number | boolean;
interface IHasToString {
toString(): string;
}
let str: IHasToString = "hello";
interface IFruit1 {
color: String;
taste: String;
size: number;
}
interface IFruit2 {
color: String;
taste: String;
}
let f1!: IFruit1;
let f2!: IFruit2;
f2 = f1;
let a = (a: string, b: string): string => "abc";
let b = (a: string): string => "abc";
class GrandParent {
house: string = "房子";
}
class Parent extends GrandParent {
money: string = "钱";
}
class Son extends Parent {
play: string = "玩";
}
function getFn(cb: (val: Parent) => Parent) {
}
getFn((val: Parent) => new Parent());
function getFn1(cb:(val: number | boolean) => string | boolean) {
}
getFn1((val:boolean | number | string):boolean => false)
enum A {
}
enum B{
}
let c2:A;
let d2:B;
class Animal {
private name:string
}
class Person {
private name:string
}
let animal:Animal = new Animal
let person :Person = new Person
function addSay(target:{new (...args:any[]):any}){
target.prototype.say = function(){
console.log('say')
}
}
function toUpperCase(flag:boolean){
return function(target:any,key:string){
let value = ''
Object.defineProperty(target,key,{
get(){
return flag? value.toUpperCase(): value.toLowerCase()
},
set(newValue:string){
value = newValue
}
})
}
}
function beforeDrink(str:string){
return function(target:any,key:string,descripor:PropertyDescriptor){
let oldValue = descripor.value;
descripor.value = function(){
console.log(str);
oldValue.call(target);
}
}
}
@addSay
class Person {
@toUpperCase(true)
name:string = 'ZS';
@beforeDrink('我渴了')
drink(){
console.log('喝水')
}
}
let person = new Person();
person.drink()