let p1 = {name: "steve", age: 5};
function greet <T> (obj: T) {
console.log(`Hello, my name is ${this.name}, I am ${this.age} years old.`);
}
greet(p1);
提供输出
Hello, my name is undefined, I am undefined years old.
P1是对象。我将对象传递给通用问候函数。此外,对象具有与问候函数需要的相同属性以显示输出。任何人都可以向新手TS爱好者解释为什么会变得“不确定”吗?
答案 0 :(得分:4)
您收到undefined
是因为this.name
和this.age
没有引用传递给函数的对象,而是引用了范围内的属性,这些属性显然是未定义的。
根据您提供的代码,没有理由为什么您的函数应该是通用的。您也没有将其用作通用函数。
首先,您应该为变量p1
定义一个接口。您使用的是打字稿,可确保编译时键入的安全性。
interface Person {
name: string;
age: number;
}
现在您可以使用此界面初始化变量
const p1: Person = {name: "steve", age: 5};
这将强制p1
类型为Person
。它也是常数,这仅意味着您不能将其重新分配给p1,但是仍然可以更改其属性。
同样,您的函数不必是通用的,但您应该为参数提供类型,以便您的函数知道其处理的内容。
function greet(a_oPerson: Person): void {
console.log(`Hello, my name is ${a_oPerson.name}, I am ${a_oPerson.age} years old.`);
}
最后,您应该相应地命名参数,并提供一个返回类型,您可以使用typescript(即使它只是空的)也可以。
完整示例:
interface Person {
name: string;
age: number;
}
const p1: Person = {name: "steve", age: 5};
function greet(a_oPerson: Person): void {
console.log(`Hello, my name is ${a_oPerson.name}, I am ${a_oPerson.age} years old.`);
}
greet(p1);
答案 1 :(得分:1)
如果您无法执行@Mik所建议的另一种选择,则是类型警卫
interface CertainObjectType {
name: string;
age: number;
}
let p1 = {name: "steve", age: 5};
function isCertainObjectType(obj: any): obj is CertainObjectType {
return obj.name !== undefined;
}
function greet<T> (obj: T) {
if(isCertainObjectType(obj)) {
console.log(`Hello, my name is ${obj.name}, I am ${obj.age} years old.`);
}
}
greet(p1);
function greet1<T>(this: T) {
if(isCertainObjectType(this)) {
console.log(`Hello, my name is ${this.name}, I am ${this.age} years old.`);
}
}
greet1.bind(this)();
答案 2 :(得分:1)
TypeScript只是将静态类型系统添加到JavaScript。在JavaScript中,您的greet()
函数采用名为obj
的参数,然后完全忽略它;相反,您使用的是this
,其值不太可能对您有用。因此,您需要使用obj
而不是this
,因为其他答案正确指出了。
还指出,您似乎在这里不需要泛型。您只需将obj
设为具体类型{name: string, age: number}
,它就会起作用:
function greet(obj: { name: string, age: number }) {
console.log(`Hello, my name is ${obj.name}, I am ${obj.age} years old.`);
}
greet()
和p1
一起使用:
greet(p1); // okay
但是如果您用无法分配给所需类型的东西来调用它,就会抱怨:
greet({ name: "the ageless one" }) // error, age is missing
,并且如果您由于excess property checking而传入具有多余属性的对象文字:
greet({ name: "one-eyed jack", age: 45, eyes: 1 }) // excess property warning,
// eyes not expected
如果您真的要对该函数使用泛型,则可能应该在类型参数T
上使用generic constraint,以便编译器知道它将具有字符串值name
和数字值age
属性:
function greet<T extends { name: string, age: number }>(obj: T) {
console.log(`Hello, my name is ${obj.name}, I am ${obj.age} years old.`);
}
因此T
的实现内部仍不完全知道greet()
,但是我们知道它必须是{name: string, age: number}
的某种子类型,因此当我们阅读时没有编译器错误name
的{{1}}和age
属性。
调用obj
之所以有效,是因为greet(p1)
符合约束条件:
p1
而且,像以前一样,如果您传递的内容不符合约束条件,则会出现错误:
greet(p1); // okay
最后,如果您传递了比约束更具体的内容(例如额外属性),则不会出现错误,并且greet({ name: "the ageless one" }) // error, age is missing
将被推断为更具体的类型:
T
好的,希望能有所帮助;祝你好运!