网站开发与设计培训的就业前景石家庄网站优化多少钱

当前位置: 首页 > news >正文

网站开发与设计培训的就业前景,石家庄网站优化多少钱,ip查询网站,网站规划与建设的案例分析函数类型表达式 function hello(x: string) {console.log(x) } //greeter函数的参数是一个函数fn#xff0c;fn也有一个string类型参数#xff0c;无返回值。 function greeter(fn: (a: string) void) {fn(hello) } greeter(hello)也可以把定义参数类型的语句单独提取出…函数类型表达式 function hello(x: string) {console.log(x) } //greeter函数的参数是一个函数fnfn也有一个string类型参数无返回值。 function greeter(fn: (a: string) void) {fn(hello) } greeter(hello) 也可以把定义参数类型的语句单独提取出来。 function hello(x: string) {console.log(x) } type Hello (a: string) void function greeter(fn: Hello) {fn(hello) } greeter(hello)调用签名 上述例子描述了函数可调用性此外函数还具有属性。函数表达式不能声明函数的属性如果我们想描述函数可以做什么可以为函数设置属性及调用签名。 type DescriptionFunction {//函数的属性和属性的类型description: string//(函数参数名参数类型)函数返回值类型(someArg: number): boolean } function doSomething(fn: DescriptionFunction) {console.log(fn.description returned fn(4)) }function test(someArg: number) {return someArg 3 } test.description haha doSomething(test)同理你可以自己添加其他属性和参数 type DescriptionFunction {description: stringtotal: number(someArg: number, otherArg: string): string } function doSomething(fn: DescriptionFunction) {console.log(fn.description fn.total returned fn(4, other)) }function test(someArg: number, other: string) {return someArg other } test.total 0 test.description 函数的描述属性 doSomething(test) 构造签名 在调用签名中可以使用new关键字来编写构造签名。 type SomeConstructor {new (a: string): object//笼统的说函数类型是new(string类型的参数)返回值是一个object } function constructObj(fn: SomeConstructor) {return new fn(string)//调用时也不能少new关键字。 }可选参数、以及函数参数不同和返回值不同等情况都会导致函数类型不同你可以使用这些特性来定义一个复杂的函数类型。 //需要保证每种定义不重合。 interface CallOrConstruct {(n?: number): string//这个函数可以是不接收参数或接收number参数并返回string的类型(x: string): boolean//这个函数可以是接收string参数返回boolean值的类型new (s: string): Date//这个函数可以是构造函数并且需要接收一个string参数返回Date值。 } function doSomeing(fn: CallOrConstruct) {//这里只是举例调用具体能怎么调用还得看传过来的fn参数带来一些什么样的参数。fn(1)fn(string)new fn(2022-06-01) }你可以将上面例子类比于我们经常使用的Date。传时间戳的时候它给我们返回一个时间格式字符串传某个时间字符串并使用new关键字的时候他会给我们返回一个日期对象。 泛型函数 当我们的输出类型与输入类型相关时我们就可以使用泛型函数。 定义方法使用尖括号定义泛型名称放在函数名和函数括号中间现在你可以把定义的泛型类似于一个已知的基础类型来用用来定义参数和返回值的类型。 function testType(x: Type[]): Type | undefined {return x[0] } const t1 test([1, 2, 3])//const t1: string | undefined const t2 test([1, 2, 3])//const t2: number | undefined const t3 test([])//const t3: undefined你可以使用多个泛型变量 下面编写一个map函数。接收一个数组和一个函数函数内对接收的数据进行操作返回值是一个数组。 function myMapInput, Output(arr: Input[], func: (a: Input) Output): Output[] {return arr.map(func)//这里调用的是公共的js中的map函数 } // const test1: number[] //在第一个测试案例中Input类型是numberOutput类型是number返回值类型是number[] const arr1 [1, 2, 3] const test1 myMap(arr1, (item) item 1) // const test2: string[] //在第二个测试案例中Input是objectoutput是string返回值类型是string[] const arr2 [{ id: 12, age: 12 },{ id: 23, age: 34 } ] const test2 myMap(arr2, (item) item.id)TypeScript 可以根据函数表达式的返回值推断 Input 类型参数的类型以及 Output 类型参数。 第一次调用myMapmyMap的类型推断为 function myMapnumber, number(arr: number[], func: (a: number) number): number[]第二次调用myMapmyMap的类型推断为 function myMap{id: string;age: number;}, string(arr: {id: string;age: number;}[], func: (a: {id: string;age: number;}) string): string[]类型约束 泛型函数可以处理任何类型的值。有时候我们有两个类型相关的值但是我们只能操作他的子属性我们就可以使用类型约束。 下面的test1和test2的类型是根据参数推断出来的。泛型就是将两个或多个具有相同类型的值关联起来 interface hasLength {length: number } function longerType extends hasLength(a: Type, b: Type) {if (a.length b.length) return aelse return b } const test1 longer([1, 2], [1, 2, 3]) const test2 longer(dfs, fdjask) //const test3 longer(10, 11)//errornumber类型没有length属性使用约束值的错误 泛型定义的是一种类型光满足约束的条件不行还得是真真确确的类型。 让我们看下面这个例子泛型Type进行了约束返回值也是Type类型。 function minimumLengthType extends { length: number }(obj: Type, minimum: number): Type {if (obj.length minimum) {return obj} else {return { length: minimum } //error 不能将类型“{ length: number; }”分配给类型“Type”。} }假设上面的语法合发将会得到一个完全行不通的代码。 function minimumLengthType extends { length: number }(obj: Type, minimum: number): Type {if (obj.length minimum) {return obj} else {return { length: minimum } //error 不能将类型“{ length: number; }”分配给类型“Type”。} } //obj.lengthminimum,return { length : 4 } const arr minimumLength([1, 2, 3], 4) const x arr.slice(0)//行不通分析得知尽管对象中有length属性但是对象根本没有slice方法。 指定类型参数 下面是一个将两个数组合并的函数。 function combineType(a: Type[], b: Type[]): Type[] {return a.concat(b) } combine([1, 2], [3, 4]) combine([1, 2], [3, 4]) combine([1, 2], [3, 4])//error Type已经推断为number类型后面不能再传string类型的数组了第三个测试案例中由于 Type已经推断为number类型后面不能再传string类型的数组了。 这个时候我们就可以手动指定类型参数的值而不是让TypeScript给我们默认推断。 //combine([1, 2], [3, 4]) combinenumber | string([1, 2], [3, 4])当我们把代码改为上述模样后可以发现combine的类型推断变为 实质上这个时候Type的类型就是string|number。 function combinestring | number(a: (string | number)[], b: (string | number)[]): (string | number)[]编写良好的泛型函数指南 下推类型参数 如果可以使用类型参数本身而不是约束它。 function test1Type(arr: Type[]) {return arr[0] } function test2Type extends any {return arr[0] } //const t1: number const t1 test1([1, 2, 3]) //const t2: any const t2 test2([1, 2, 3])显然第一种写法比第二种写法要好第一种写法可以推断出返回值的类型而第二种写法推断的类型是any。 我们尽量直接使用类型而不做类型约束。 使用更少的类型参数 如果可以始终使用尽可能少的类型参数。 例如写一个过滤函数时下面第一种写法只定义了一个类型参数剩下的都是利用这个类型灵活使用最终调用也能准确地推断出返回值地类型。 function filter1Type(arr: Type[], func: (arg: Type) boolean): Type[] {return arr.filter(func) } const t1 filter1([-1, 2, 3], (item) item 0) 对于第二种写法这里多写了一个类型参数Func还对Func做了类型限制用起来两者得到的结果是一样的但是Func并没有关联两个或多个值的类型它没有做任何事情只会让读者更难理解。 function filter2Type, Func extends (arg: Type) boolean(arr: Type[], func: Func): Type[] {return arr.filter(func) } const t2 filter2([-1, 2, 3], (item) item 0)类型参数应该出现两次 如果一个类型参数只出现在一个位置强烈重新考虑是否真的需要它 有时候我们可能忘了函数是不需要泛型的。 function greetStr extends string(s: Str) {console.log(Hello, s); } greet(world);我们可以更容易地编写一个更简单的版本。 function greet(s: string) {console.log(Hello, s); }泛型用于关联多个值的类型。如果一个泛型只在函数签名中使用一次它就没有任何关系。这包括推断的返回类型 例如如果 Str 是 greet 的推断返回类型的一部分它将关联参数和返回类型因此尽管在书面代码中只出现一次但它会被使用两次。 可选参数 //问号可传可不传可传undefined function f1(n?: number): void {console.log(n) } f1() f1(1) f1(undefined)//指定默认值 function f2(x: number 10) {console.log(x) } f2(1)回调中的可选参数 为回调编写函数类型时切勿编写可选​​参数除非你打算在不传递该参数的情况下调用该函数。 如果你在函数类型中声明了一个参数为可选参数那么在使用这个函数类型时传递该参数是可选的。如果你不打算在调用函数时传递该参数但是却在函数类型中将其声明为可选参数可能会导致一些问题。 这会导致你有可能传递了可选参数但是函数里面没有没有调用。或者你没传递可选参数但是函数里面调用了。这带来了一些难以查找的错误。 function myForEach(arr: any[], callback: (arg: any, index?: number) void) {for (let i 0; i arr.length; i) {// callback(arr[i], i)callback(arr[i])} } myForEach([1, 2, 3], (item) console.log(item)) myForEach([1, 2, 3], (item, index) console.log(item, index))函数重载 我们希望可以以各种参数、参数个数、参数类型来调用函数。这可以使用函数重载来实现。 函数签名一定多于两个。 函数只有一个实现签名但是这个签名不能直接调用。 函数的调用是按照函数的重载签名定义来的下面两个函数签名中只有传递一个参数的或者传递三个参数的。最后一种调用传递了两个参数是不可行的。 //函数的重载签名 function makeDate(timestamp: number): Date function makeDate(m: number, d: number, y: number): Date //函数的实现签名 function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {if (d ! undefined y ! undefined) {return new Date(y, mOrTimestamp, d)} else {return new Date(mOrTimestamp)} } //这里调用的都是函数的重载签名不是函数的实现签名 const d1 makeDate(1798329749) const d2 makeDate(6, 11, 2022) //error没有需要 2 参数的重载但存在需要 1 或 3 参数的重载 //const d3 makeDate(1, 2)重载签名和实现签名 重载签名没有方法体只有函数名、函数参数及类型、函数返回值及类型。 实现签名兼容所有函数签名有方法体。 从外部看不到实现的签名。在编写重载函数时你应该始终在函数实现之上有两个或多个签名。 实现签名还必须与重载签名兼容。 例如下面这个例子就是实现签名与重载签名在函数参数类型不兼容。 function fn(x: boolean): void; function fn(x: string): void;//error此重载签名与其实现签名不兼容 function fn(x: boolean) {}稍微改动一下实现签名的函数参数即可 function fn(x: boolean | string) {}下面这个例子是实现签名与重载签名在返回值类型部分不兼容。 function fn(x: string): string; function fn(x: number): boolean; function fn(x: string | number) {return oops; }同样改动一下实现签名的返回值类型即可 function fn(x: string | number): string | boolean {return oops }需要注意的是上面的改动能使函数正常调用但是函数调用的时候不能传递一个不确定类型的值。例如fn(Math.random() 0.5 ? dfs : true) 这将会导致报错原因TypeScript只会将函数调用解析为一种重载。传递可能值会混淆TypeScript的判读。 编写好的重载 尽可能使用联合类型的参数而不是重载。 下面是一个返回字符串或数组长度的函数。 function len(s: string): number function len(arr: any[]): number function len(x: any) {return x.length } len() len([0]) len(Math.random() 0.5 ? hello : [0]) //error没有与此调用匹配的重载。我们不能使用可能是字符串或数组的值来调用函数重载因为TypeScript只能将函数调用解析为单个重载。 我们将函数改为非重载版本即可。 function len(x: any[] | string) {return x.length; }在函数中声明this TypeScript 将通过代码流分析推断函数中的 this 应该是什么。 interface DB {filterUsers(filter: (this: User) boolean): User[]; }const db getDB(); const admins db.filterUsers(function (this: User) {return this.admin; });这种模式在回调风格的 API 中很常见其中另一个对象通常控制何时调用你的函数。 请注意你需要使用 function 而不是箭头函数来获得此行为。 其他需要了解的类型 void void 表示不返回值的函数的返回值。只要函数没有任何 return 语句或者没有从这些返回语句返回任何显式值它就是推断类型。 function test1() {return } //function test1(): voidfunction test2() {console.log() } //function test2(): void 在 JavaScript 中不返回任何值的函数将隐式返回值 undefined。但是void 和 undefined 在 TypeScript 中不是一回事。 object 特殊类型 object 指的是任何非基础值string、number、bigint、boolean、symbol、null 或 undefined。 object和{}不同。 object和Object也不同在TypeScript中你可能永远用不到Object。 在JavaScript中函数值是对象它们有属性在它们的原型链中有 Object.prototype是 instanceof Object你可以在它们上调用 Object.keys等等。 在 TypeScript 中函数类型被视为 object。 unknown unknown类型代表任何值作用类似于any类型但是比any类型安全因为使用unknown做任何事情都是不合法的。 你可以描述一个返回未知类型值的函数而不需要使用any。 function safeParse(s: string): unknown {return JSON.parse(s) } never 有些函数从不返回值可以使用never定义返回值类型。 function fail(msg: string): never {throw new Error(msg) }never 类型表示从未观察到的值。在返回类型中这意味着函数抛出异常或终止程序的执行。 TypeScript确定联合中没有任何类型时也会返回never。 function fail(msg: string): never {throw new Error(msg) } function fn(x: string | number) {if (typeof x string) {console.log(x) //(parameter) x: string} else if (typeof x number) {console.log(x) // (parameter) x: number} else {console.log(x) // (parameter) x: never} }Function 全局类型 Function 描述了 bind、call、apply 等属性以及 JavaScript 中所有函数值上的其他属性。 它还具有 Function 类型的值始终可以被调用的特殊属性这些调用返回 any。 function test(f: Function): void {const x f(1, 2, 3) //const x: any }这是不安全的如果函数可以接收任何类型的参数且不需要返回值那么建议用()void替换Function。 剩余形参和实参 剩余形参 除了使用可选参数或重载来制作可以接受各种固定参数计数的函数之外我们还可以使用剩余参数定义接受无限数量参数的函数。 剩余参数出现在所有其他参数之后并使用 … 语法 让我们来分析下面这段代码。其中m就是10n就是1234组成的数组。 返回值n的所有数乘以m再返回一个数组最终结果为[10203040] function multiply(m: number, …n: number[]) {return n.map((item) item * m) } const a multiply(10, 1, 2, 3, 4)剩余实参 相反我们可以使用扩展语法从可迭代对象例如数组中提供可变数量的参数。例如数组的 push 方法接受任意数量的参数 const arr1 [1, 2, 3]; const arr2 [4, 5, 6]; arr1.push(…arr2);TypeScript 并不假定数组是不可变的。 下面这段代码就会报错atan2是一个只接收两个参数的函数TypeScript认为args是可变的故TypeScript不允许将一个可变的数组传递给一个只能接收两个参数的函数。 const args [8, 5] const angle Math.atan2(…args)这种情况使用as const就可以解决了。 const args [8, 5] as const const angle Math.atan2(…args) 参数解构 你可以使用参数解构来方便地将作为参数提供的对象解包到函数体中的一个或多个局部变量中。 和JavaScript中的解构差不多就是多了类型的定义。 type ABC { a: number; b: number; c: number } function sum({ a, b, c }: ABC) {console.log(a b c) } sum({ a: 1, b: 2, c: 3 })函数的可赋值性 返回类型void 具有 void 返回类型 (type voidFunc () void) 的上下文函数类型当实现时可以返回任何其他值但会被忽略。 因此下列写法是有效的。 type voidFunc () voidconst f1: voidFunc () {return true } const f2: voidFunc () true const f3: voidFunc function () {return true } const v1 f1();//const v1: void const v2 f2();//const v1 f1() const v3 f3();//const v1 f1()我们可以发现尽管TypeScript允许我们在函数类型的返回类型为void的情况下返回其他值但是我们返回的值是不生效的。 当字面量函数定义具有 void 返回类型时该函数不得返回任何内容。 function f2(): void {return true //不能将类型“boolean”分配给类型“void” }const f3 function (): void {return true //不能将类型“boolean”分配给类型“void” }注意这里的void是我们手动加在函数上的是函数的返回类型。上面的voidFunc是我们定义的某种函数的类型。 上面是直接定义整个函数的类型下面定义的是函数的返回值类型。