我正在使用新方法扩展String原型链,但是当我尝试使用它时,它会抛出一个错误:property 'padZero' does not exist on type 'string'
。有人能为我解决这个问题吗?
代码如下。您还可以在Typescript Playground中看到相同的错误。
interface NumberConstructor {
padZero(length: number);
}
interface StringConstructor {
padZero(length: number): string;
}
String.padZero = (length: number) => {
var s = this;
while (s.length < length) {
s = '0' + s;
}
return s;
};
Number.padZero = function (length) {
return String(this).padZero(length);
}
答案 0 :(得分:63)
此答案适用于TypeScript 1.8+。这类问题有很多其他答案,但它们似乎都涵盖旧版本。
在TypeScript中扩展原型有两个部分。
声明新成员,以便它可以传递类型检查。您需要声明一个与要修改的构造函数/类同名的接口,并将其放在正确的声明的命名空间/模块下。这称为范围扩充。
以这种方式扩展模块只能在特殊声明.d.ts
文件*中完成。
//in a .d.ts file:
declare global {
interface String {
padZero(length : number) : string;
}
}
外部模块中的类型具有包含引号的名称,例如"bluebird"
。
Array<T>
和String
等全局类型的模块名称为global
,没有任何引号。但是,在许多版本的TypeScript中,您可以完全放弃模块声明并直接声明接口,具有类似的内容:
declare interface String {
padZero(length : number) : string;
}
在1.8之前的某些版本中也是这种情况,在2.0之后的某些版本中也是如此,例如最新版本2.5。
请注意,除declare
文件中的.d.ts
语句外,您不能拥有任何内容,否则无效。
这些声明会添加到程序包的环境范围内,因此即使您不直接import
或///<reference
文件,它们也会应用于所有TypeScript文件。但是,您仍然需要导入在第二部分中编写的实现,如果忘记执行此操作,则会遇到运行时错误。
*从技术上讲,您可以通过此限制并将声明放在常规.ts
文件中,但这会导致编译器出现一些挑剔的行为,并且不建议这样做。
第2部分实际上正在实现该成员并将其添加到它应该存在的对象中,就像在JavaScript中一样。
String.prototype.padZero = function (this : string, length: number) {
var s = this;
while (s.length < length) {
s = '0' + s;
}
return s;
};
请注意以下几点:
String.prototype
而不是String
,而不是String
构造函数,而不是原型。function
而不是箭头函数,因为function
将从调用它的位置正确接收this
参数。箭头函数将始终使用与它声明的位置相同的this
。有一次我们不希望这种情况发生在扩展原型时。this
,因此编译器知道我们期望的this
类型。此部分仅适用于TS 2.0+。如果您正在编译1.8-,请删除this
注释。如果没有注释,this
可能会隐式输入any
。在TypeScript中,declare
构造将成员添加到环境范围,这意味着它们出现在所有文件中。为了确保第2部分的实现能够连接起来,import
该文件就在您的应用程序开始时。
您可以按如下方式导入文件:
import '/path/to/implementation/file';
不导入任何东西。您也可以从文件中导入某些内容,但不需要导入您在原型上定义的函数。
答案 1 :(得分:17)
这是一个工作示例,一个简单的Camel Case字符串修饰符。
在我的项目 index.d.ts 中
interface String {
toCamelCase(): string;
}
在我的根.ts
可访问的地方
String.prototype.toCamelCase = function(): string {
return this.replace(/(?:^\w|[A-Z]|-|\b\w)/g,
(ltr, idx) => idx === 0
? ltr.toLowerCase()
: ltr.toUpperCase()
).replace(/\s+|-/g, '');
};
这就是我需要做的就是让它在打字稿^2.0.10
中运行。
我像str.toCamelCase()
<强>更新强>
我意识到我也有这种需要,而这就是我所拥有的
interface String {
leadingChars(chars: string|number, length: number): string;
}
String.prototype.leadingChars = function (chars: string|number, length: number): string {
return (chars.toString().repeat(length) + this).substr(-length);
};
所以console.log('1214'.leadingChars('0', 10));
让我0000001214
答案 2 :(得分:7)
对我来说,以下内容使用TypeScript 2.8.4在Angular 6项目中进行了工作。
在Typings.d.ts文件中添加:
interface Number {
padZero(length: number);
}
interface String {
padZero(length: number);
}
注意:无需“声明全局”。
在名为string.extensions.ts的新文件中添加以下内容:
interface Number {
padZero(length: number);
}
interface String {
padZero(length: number);
}
String.prototype.padZero = function (length: number) {
var s: string = String(this);
while (s.length < length) {
s = '0' + s;
}
return s;
}
Number.prototype.padZero = function (length: number) {
return String(this).padZero(length)
}
要使用它,请先将其导入:
import '../../string.extensions';
很显然,您的import语句应指向正确的路径。
在类的构造函数或任何方法中:
var num: number = 7;
var str: string = "7";
console.log("padded number: ", num.padZero(5));
console.log("padding string: ", str.padZero(5));
答案 3 :(得分:3)
如果要扩展$Records = Import-Csv -Path C:\server2.log -Delimiter "," -Header Date, Message
$FixedRecords = for($i = 0; $i -lt $Records.Count - 1; $i++){
$NextRecord = $Records[$i + 1]
if($NextRecord.Date -notmatch '^\d{4}-\d{2}-\d{2}'){
# Append next record's message to the current one
$Records[$i].Message += $NextRecord.Message
# Skip ahead to the next record
$i++
}
$Records[$i]
}
而不是class
,请扩展构造函数:
instance
*如果您在declare global {
interface StringConstructor {
padZero(s: string, length: number): string;
}
}
String.padZero = (s: string, length: number) => {
while (s.length < length) {
s = '0' + s;
}
return s;
};
console.log(String.padZero('hi', 5))
export {}
中declare global
并且不导出任何内容,则必须在底部进行空导出。这将强制文件成为模块。 *
如果要在.ts
(又名instance
)上使用该功能,
prototype