-
JAVA重载函数返回类型_ts中可以按照返回值类型来进行函数重载么?
2021-03-15 19:45:55new List() const elem = list.remove(0) const boolean = list.remove({} as Elem) 虽然重载可以解决这个问题,但是按着问题描述 elem 是一个 any 类型,那么就意味着它可以是一个数字,那么当它是数字时是应该走...type Elem = {}
class List {
elems: Elem[] = []
remove(index: number): Elem
remove(elem: Elem): boolean
remove(indexOrElem: number | Elem): Elem | boolean {
// TODO 该函数有歧义(当参数与数组元素均为number类型时,是按照index还是ele方式来处理),暂定先按index来处理
if (typeof indexOrElem === 'number') {
const [ deletedEle ] = this.splice(indexOrElem, 1)
return deletedEle
} else {
const index = this.indexOf(indexOrElem)
if (index === -1) {
return false
} else {
this.remove(index)
return true
}
}
}
splice(index: number, deleteCount: number): Elem[] {
return this.elems
}
indexOf(ele: Elem): number {
return 0
}
}
const list = new List()
const elem = list.remove(0)
const boolean = list.remove({} as Elem)
虽然重载可以解决这个问题,但是按着问题描述 elem 是一个 any 类型,那么就意味着它可以是一个数字,那么当它是数字时是应该走索引的逻辑还是元素的逻辑呢?这样这个 API 就很保证稳定的工作,所以个人不太建议设计这样的 API。
可以考虑将 API 拆细一些,保证功能的单一。
remove(elem: Elem) {
const index = this.indexOf(elem)
if (index === -1) {
return false
} else {
this.remove(index)
return true
}
}
removeByIndex(index: number) {
const [ deletedEle ] = this.splice(index, 1)
return deletedEle
}
-
ts学习第五篇 抽象类和重写重载继承多态
2020-12-22 21:48:47// 抽象类和重写重载继承多态 export {} // 抽象类.抽象方法不包括具体实现, 必须在子类里面实现; 抽象方法必须写在抽象类里面 abstract class Animal { //抽象类 name: string abstract speak():void //抽象...// 抽象类和重写重载继承多态 export {} // 抽象类.抽象方法不包括具体实现, 必须在子类里面实现; 抽象方法必须写在抽象类里面 abstract class Animal { //抽象类 name: string abstract speak():void //抽象方法 } class Cat extends Animal { speak(): void { //重写父类的方法speak console.log('喵喵喵'); } } //重写: 子类重写继承自父类的方法 //重载: 函数的重载 function double(val:string) function double(val:number) function double(val:any){ if(typeof val === 'number') { return val*2 } else if(typeof val === "string") { return val + val } } double(2) double('1') // double(true) //加上上面两句之后这里如果传布尔值就会报错, 也即函数的重载 // 继承和多态 // 继承: 主要是通过extends // 多态: 同一个方法,不同的子类有不同的实现, 如父类的speak方法,子类Cat的实现如上, 而其他子类的实现如下: class Dog extends Animal { speak(): void { //重写父类的方法speak console.log('汪汪汪'); } }
-
TS --- 函数(定义,参数,重载) 笔记
2020-08-02 19:38:42一。函数的定义 二。参数(可选参数/默认参数/剩余参数) //函数的参数 function add(x : number,y : number) : number{ return x + y } //可选参数? function show(name,age?...方法的重载一。函数的定义
二。参数(可选参数/默认参数/剩余参数)
//函数的参数
function add(x : number,y : number) : number{
return x + y
}
//可选参数?
function show(name,age? : number) : void{
console.log(name,age)
}
show('zs')
//默认参数
注意:可选参数,一般都要放在参数列表的最后面
function show1(name,age : number = 20) : void{
console.log(name,age)
}
show('zs',10) //传了参数,用传的参,没有传参,采用默认参数
//剩余参数
//剩余参数(不确定有多少个参数)
function add1(x1,x2,...x : number[]) : number{
let sum = 0
for(let i = 0;i<x.length;i++){
sum += x[i]
}
return x1 + x2 + sum
}
let sum = add1(1,2,3,4,5,6,7,8)
console.log(sum)
三。方法的重载
-
require 动态加载_TS/JS 模块自加载与热重载
2020-12-16 17:00:15自动加载与热重载:模块代理 上面已经对热重载的实现原理进行了基本的介绍,下面将结合更实际和简洁的方式,来实现一个完整的自动加载和热重载模块的方案:模块代理。结合全局命名空间,该方案能够利用声明合并来在...很多时候,特别是在开发过程中,我们希望能够不需要频繁重启服务就立即应用改动的代码。但在常驻内存的服务器应用中,要实现这种需求并不简单。
强引用和弱引用
因为常驻内存的自然特性,变量存在强引用的问题,特别是在像 CommonJS 这样的模块加载方案中,一旦 `require/import` 的模块被赋值到了新的变量中,它就自动形成了对模块的“拷贝”,即原模块发生改变之后,在导入的地方,这个改变将毫无作用。例如下面的例子:
// app.ts const app = { name: "app" /* ... */ }; export default app; // index.ts import app from "./app"; console.log(app.name); // => app
现在,修改 app.ts 中的代码为如下这样子:
const app = { name: "my-app" /* ... */ }; export default app;
这并没有任何作用,因为如果不重启进程,新代码将不会被运行。但 NodeJS 提供了重载模块的方案。默认地,NodeJS 将模块缓存到 `require.cache` 中,因此,理论上,只要删除缓存,并重新导入即可。因此,开发者可以实现下面这样的逻辑,用来监听文件改变,并自动重载模块。
import { watch } from "chokidar"; // chokidar 是一个兼容更多平台的文件监听模块 watch(__dirname).on("change", (filename) => { delete require.cache[filename]; require(filename); });
但实际上这毫无作用,因为在 index.ts 中,`import app from "./app";` 创建了一个对模块的
强引用(不完整的拷贝),当模块本身发生了改变并重载(重新赋值到缓存中),强引用就会立即变成完整的拷贝,就像下面这样:var cache = { name: "app" }; var copy = cache; // 如果 cahce 被重载 cache = { name: "my-app" }; // copy 将不会有任何改变 console.log(capy.name) // => app
要实现缓存重载后原来的引用也能够发生改变,则需要通过"弱引用"导入。即每一处使用导入对象的地方,都重新检查缓存,例如重新调用 `require`,类似下面这样:
console.log(require("./app").default.name);
如此一来,当缓存被重载,`require` 就会返回新的对象。
自动加载与热重载:模块代理
上面已经对热重载的实现原理进行了基本的介绍,下面将结合更实际和简洁的方式,来实现一个完整的自动加载和热重载模块的方案:模块代理。结合全局命名空间,该方案能够利用声明合并来在 TypeScript 中享受到诸如类型提示和类型检查的优势。
首先,利用声明合并来定义所需的全局接口类型,使它们能够在项目的任何地方都可以直接使用。declare global { interface ModuleConstructor<T> { new (...args: any[]) => T; /** 用于获取模块单例 */ getInstance?(): T; } interface ModuleProxy<T, R1 = any, R2 = any, R3 = any, R4 = any, R5 = any> { /** 模块的名称(包快命名空间) */ readonly name: string; /** 模块的路径(不包含后缀名) */ readonly path: string; /** 模块的构造函数(仅支持默认导出类) */ readonly ctor: ModuleConstructor<T>; /** 创建模块的实例(相当于 new this.ctor()) */ create(): T; create(arg1: R1): T; create(arg1: R1, arg2: R2): T; create(arg1: R1, arg2: R2, arg3: R3): T; create(arg1: R1, arg2: R2, arg3: R3, arg4: R4): T; create(arg1: R1, arg2: R2, arg3: R3, arg4: R4, arg5: R5): T; create(...args: any[]): T; /** 设置/获取模块的 singleton 实例(单例) */ instance(ins?: T): T; } }
接下来,需要实现真正的 ModuleProxy 构造器,并且它支持通过“点语法”来无限延展,从而形成命名空间,来实现自动加载模块(就像在其他语言如 PHP 或者 Java 中那样)。
import { nrmalize } from "path"; export class ModuleProxy { private root: { name: string, path: string }; private children: { [name: string]: ModuleProxy } = {}; constructor( readonly name: string, path: string, private singletons: { [name: string]: any } = {}, ) { this.root = { name: name.split(".")[0], path: normalize(path) }; } }
为了支持点语法自动延展命名空间,我这里使用 js-magic 包并实现 `__get` 和 `__has` 魔术方法,从而在访问不存在的属性时,能够自动生成新的模块代理实例。
import { applyMagic } from "js-magic"; @applyMagic export class ModuleProxy { // ... protected __get(prop: string) { if (prop in this) { return this[prop]; } else if (prop in this.children) { return this.children[prop]; } else if (typeof prop != "symbol") { // 当访问不存在的实例时,创建并返回新的 ModuleProxy 实例 return (this.children[prop] = new ModuleProxy( (this.name && `${this.name}.`) + String(prop), // 扩展名称 this.root.path, this.singletons, )); } } protected __has(prop: string) { return (prop in this) || (prop in this.children); } }
接下来,利用 Getter 来实现访问模块构造函数,其方案是优先访问缓存,当缓存不存在时,通过调用 `require` 函数来动态导入模块,从而实现模块代理的自动加载机制。
import { resolve } from "path"; export class ModuleProxy { // ... get path(): string { // 计算模块的路径 return resolve(this.root.path, ...this.name.split(".").slice(1)); } get ctor(): ModuleConstructor<any> { let { path } = this; // 同时检查 js 和 ts 模块,以兼容 node 和 ts-node 环境 let mod = require.cache[path + ".ts"] || require.cache[path + ".js"]; if (!mod) { // 如果缓存不存在,则导入 mod = require(path); // 仅支持默认导出,并且必须是一个类 (函数) if (!mod.default || typeof mod.default !== "function") { throw new TypeError(`Module ${this.name} is not a constructor.`); } } else { mod = mod.exports; } return mod.default; } }
然后实现 `create()` 和 `instance()` 方法,不过它们是额外的支持,如果不需要,则完全可以忽略它们(需要同时删除全局 ModuleProxy<T> 接口中的方法)。
export class ModuleProxy { // ... create(...args: any[]) { return new this.ctor(...args); } instance(ins?: any) { if (ins) { return (this.singletons[this.name] = ins); } else if (this.singletons[this.name]) { return this.singletons[this.name]; } else { let ins: any; // 使用多种方式尝试获取单例 if (typeof this.ctor.getInstance === "function") { ins = this.ctor.getInstance(); } else { try { ins = this.create(); } catch (err) { ins = Object.create(this.ctor.prototype); } } return (this.singletons[this.name] = ins); } } }
最后需要实现的是文件监听和热重载功能,即在检测到文件发生改变的时候,能够立即删除模块的缓存,从而在下一次访问 `ctor` 属性的时候重新导入模块。
export class ModuleProxy { // ... // 提供可选的 listener 回调函数以便能够自定义 watch(listener?: (event: "change" | "unlink", filename: string) => void) { let { path } = this.root; let clearCache = (event: string, filename: string, cb: Function) => { let name = this.resolve(filename); if (name) { delete this.singletons[name]; // 删除单例缓存 delete require.cache[filename]; // 删除模块缓存 cb && cb(event, filename); } }; // 同时监听文件改变和删除事件 return watch(path, { awaitWriteFinish: true, followSymlinks: false }).on("change", (filename) => { clearCache("change", filename, listener); }).on("unlink", (filename) => { clearCache("unlink", filename, listener); }).on("unlinkDir", dirname => { dirname = dirname + sep; for (let filename in require.cache) { if (startsWith(filename, dirname)) { clearCache("unlink", filename, listener); } } }); } }
创建根实例
要使用这个模块代理功能,首先需要创建一个根实例,并将其赋值到 global 对象上,这样在项目的任何地方都可以使用这个根实例,来通过点语法(命名空间)代理访问模块。
const app = global["app"] = new ModuleProxy("app", __dirname); // 开启文件监听和热重载 app.watch();
为了在 TypeScript 中使用,还需要通过声明合并将 `app` 作为一个命名空间合并到 global 命名空间下。
declare global { namespace app { } }
创建模块与命名空间
然后,就可以创建任何需要自动加载和热重载的模块,模块的路径和命名空间一一对应,为了在 TypeScript 中使用类型提示和类型检查,同样的,需要将其合并到全局命名空间,并且文件必须将模块类做为默认导出。
// bootstrap.ts declare global { namespace app { const bootstrap: ModuleProxy<Bootstrap> } } export default class Boostrap { init() { // ... } }
如果一个模块在文件夹中,则需要将文件夹名称作为一个新的命名空间:
// services/user.ts declare global { namespace app { namespace services { const user: ModuleProxy<User, string>; } } } export default class User { constructor(protected name: string) { } getName() { return this.name; } }
然后在项目的任何地方,就可以直接通过命名空间来访问模块了,并享受到热重载带来的好处。
app.bootstrap.instance().init(); var user = app.services.user.create("Mr. World"); console.log(user.getName()); // => Mr. World
注意事项
利用命名空间,模块代理能够进行动态加载和热重载,但任何时候都需要注意,不要将命名空间返回的模块构造函数赋值给最外层作用域的变量,因为如果上下文模块不支持热重载的话,它又会回到强引用的陷阱当中。
最终实现
Alar 是一个实现了上述逻辑的简单框架,并在其基础上添加了模块代理的远程服务 (IPC/RPC) 支持,如果需要了解更多细节,可以在 GitHub 上查看它,或者直接查看我的下一篇介绍该框架的文章《使用 Alar 框架轻松实现热重载和分布式 NodeJS 应用》。
hyurl/alargithub.comAyonium:使用 Alar 框架轻松实现热重载和分布式 NodeJS 应用zhuanlan.zhihu.com -
[unity]解决子类重载基类方法时index.d.ts报错
2020-12-26 05:26:39<div><p>该提问来源于开源项目:Tencent/puerts</p></div> -
没有与指定类型匹配的重载函数_TS学习笔记(四):函数
2020-12-06 01:18:10重载 TypeScript 允许我们定义多个函数类型定义来进行函数重载,编译器会根据定义列表去处理函数的调用。 function foo(x: number): string function foo(x: string): string function foo(x): any { if (typeof x ... -
ts
2020-09-18 18:36:02// 重载 // function cz(name: string): any // function cz(name: string, age?: number): any { // if (age) { // return `我叫${name}今年${age}岁`; // } else { // return `我叫${name}`; // } // } // // ... -
ts函数(可选参数、默认参数、函数声明、可变参数、函数重载)
2019-02-23 11:41:19* 5)函数重载 * 1.先声明 * 2.用any写实现(加很多判断) */ function test6(n: string): void; function test6(n: number): number; function test6(c: any): void | number { if(typeof c == "number"){ }... -
TS笔记
2021-02-01 11:27:46TS笔记基础介绍作用编译运行ts数据类型函数TS类todoList ...8. 提供一些语法糖,方便实践面向对象的编程(类,接口,枚举,泛型,方法重载) 编译运行 npm install -g typescript 手动:tsc *.js 自动:配合vscod -
【ts】ts学习笔记
2020-06-14 17:17:37一、函数重载 // 函数重载 function add(...rest: number[]):number; function add(...rest: string[]):string; function add(...rest: any):any { let first = rest[0]; if(typeof first === 'number') { return... -
java之重载和重写
2020-08-12 18:00:33方法重载: 方法重载是指方法名和方法的返回类型都相同,但方法参数不一样. 参数不一样体现在参数个数、参数类型以及参数类型的顺序 不一样(三条满足一条即不一样). 举个例子: Test.java public class Test { public... -
MPEG-2 TS学习(六)tsfilter源码阅读(3)TS的解析流程
2017-02-26 21:26:131、读取一个TS包,注意Packet重载了>>操作符 2、如果TS包的PID等于0,表示TS包中装的是PAT (1)从TS包中把PAT读取出来,PAT也重载了>>操作符 (2)把PAT中的program读取出来 (3)遍历所有的program -
Scala重载解析
2015-06-01 17:11:54如果一个标识符或选择e引用了数个类的成员,则将使用引用的上下文来推断唯一的成员。使用的方法将依赖于e是否被用作一个函数。...否则,设Ts是通过用未定义类型来类型化每个参量所得到的类型向量。首先要... -
TypeScript基础入门 - 函数 - 重载
2018-08-21 22:28:17TypeScript基础入门 - 函数 - 重载 项目实践仓库 https://github.com/durban89/typescript_demo.git tag: 1.2.5 为了保证后面的学习演示需要安装下ts-node,这样后面的每个操作都能直接运行看到输出的结果。 ... -
Typescript-ts 装饰器源码分析——方法装饰器
2018-02-23 22:23:24方法装饰器不能用在声明文件( .d.ts),重载或者任何外部上下文(比如declare的类)中。 方法装饰器表达式会在运行时当作函数被调用,传入下列3个参数: 对于静态成员来说是类的构造函数,对于实例成... -
ts装饰器
2020-11-17 20:13:13类装饰器重载 返回一个继承与Fal类的类,并且里面的属性与方法要一致。 属性装饰器 对于实例成员。target是类的原型对象 对于静态成员,target是类的构造函数 方法装饰器 对实例成员来说,target是类的... -
Ts_05类的标注
2021-04-20 15:39:57文章目录Ts面向对象编程思想类类的概念类的基础class构造函数成员属性与方法定义this关键字构造函数参数属性继承super关键字方法的重写与重载方法的重写(函数的参数个数和类型是一样的,但是逻辑不一样就是方法的... -
ts typescript.txt
2020-03-13 21:09:2304 Typescript中的函数 函数的定义 可选参数 默认参数 剩余参数 函数重载 箭头函数 (31分50秒).rar 05 Typescript中的类 Es5中的类和静态方法 继承 (原型链继承、对象冒充继承、原型链+对象冒充组合继承... -
C#方法重载-基于不同类型的参数的方法重载
2012-06-26 13:16:00using System;using System.Collections.Generic;using System.Linq;using System.Text; namespace ConsoleApplication7{ class Test { static void Main(string[] args) { Test ts... -
【TS】typescript 学习记录
2019-04-21 20:57:56一定要学会看英文! 命令行报错→有道词典→复制到谷歌 ...ts 主要就是为了解决 js 的一些错误,... 函数重载:可以支持多种形式的参数类型 安装 sudo apt-get install nodejs (查看版本:node -v) sudo ... -
java重载与重写的区别
2014-04-03 16:30:09方法重载: 方法重载是指方法名和方法的返回类型都相同,但方法参数不一样. 参数不一样体现在参数个数和参数类型不一样. 举个例子: Test.java ...Test ts = new Test() ; System.out.printl -
学习ts blog:对ts学习过程中的一些记录
2020-05-28 00:35:001.函数的重载 function getInfo(name: string):string; function getInfo(name: string, age: number):string; // 不符合上面两种格式会报错 function getInfo(name: any, age?: any):any { /* code... */ } 2.... -
TypeScript系列学习笔记-函数(function)之重载
2018-04-09 18:18:43回顾C#中重载的概念:1.方法重载是指在同一个类中方法同名,参数不同,调用时根据实参的形式,选择与他匹配的方法执行操作的一种...在JS中本身不支持重载的,而在TS中使用可以"变通"的支持重载:1.先申明... -
两行代码和三个C ++ 17特性:重载模式
2019-02-17 14:46:53我们来看一下C ++中的一个新模式,重载模式,以及如何在代码中实现它。 访问std::variant的模式: template<class... Ts> struct overload : Ts... { using Ts::operator()...; }; template<... -
java中重载和重写的区别是什么?
2016-02-02 20:44:03方法重载:方法重载是指方法名和方法的返回类型都相同,但方法参数不一样.参数不一样体现在参数个数和参数类型不一样.举个例子: Test.java-------------- public class Test{ public static void main(String[] args... -
typescript(三)--ts中函数
2018-07-21 14:03:33如题。 ts中函数语法大致和es6一致,因为ts中也兼容es5的语法,故es5的代码在ts中也并不会报错。又因为ts比js多了可选的类型,故ts的语法看起来更... 函数重载 箭头函数 es6 ================================... -
typescript 函数(定义、参数、重载)
2019-04-26 23:29:00代码: // 本节内容 // 1.函数的定义 // 2.参数(可选参数/默认参数/剩余参数) // 3.方法的重载 // js // function add(x,y){ // return x+y // } ...// ts // 1.函数的定义 fu... -
express-ts:TypeScript中的Docker和Kube-ready应用程序-源码
2021-02-28 07:15:12然后,设置快速重载: ./dev.sh 或者,运行: npm run ts-watch和npm run dev 在单独的终端中。 项目的TypeScript将进行增量编译,并且更改时会将静态文件复制到dist /文件夹中。 更改任何静态文件或...