打印稿:类型# 160;& # 39;字符串# 160;| & # 160;未定义# 39;& # 160;如果# 160;不是# 160;可转让的# 160;伍仟# 160;类型# 160;& # 39;字符串# 39;

当我将接口的任何属性设置为可选时,并将其成员分配给其他变量,如下所示:

interface Person {
name?: string,
age?: string,
gender?: string,
occupation?: string,
}


function getPerson() {
let person = <Person>{name:"John"};
return person;
}


let person: Person = getPerson();
let name1: string = person.name; // <<< Error here

我得到如下错误:

TS2322: Type 'string | undefined' is not assignable to type 'string'.
Type 'undefined' is not assignable to type 'string'.

如何避免这个错误呢?

641565 次浏览

试着事先找出实际值。如果person有一个有效的name,将其赋值给name1,否则赋值给undefined

let name1: string = (person.name) ? person.name : undefined;

解决方案1:删除显式类型定义

由于getPerson已经返回一个带有名称的Person,所以我们可以使用推断类型。

function getPerson(){
let person = {name:"John"};
return person;
}


let person = getPerson();

如果定义person: Person,就会丢失一条信息。我们知道getPerson返回一个具有非可选属性的对象,名为name,但将其描述为Person将使可选性恢复。

解决方案2:使用更精确的定义

type Require<T, K extends keyof T> = T & {
[P in K]-?: T[P]
};


function getPerson() {
let person = {name:"John"};
return person;
}


let person: Require<Person, 'name'> = getPerson();
let name1:string = person.name;

解决方案3:重新设计界面

所有属性都是可选的形状被称为弱类型,通常是糟糕设计的标志。如果我们将name设置为必选属性,那么问题就解决了。

interface Person {
name:string,
age?:string,
gender?:string,
occupation?:string,
}

也有同样的问题。

我发现react-scrips将"strict": true添加到tsconfig.json

在我移除它之后,一切都很好。

编辑

需要警告的是,更改此属性意味着:

不再对潜在的运行时错误发出警告。

正如PaulG在评论中指出的那样!谢谢!

只有在你完全理解"strict": false的影响时才能使用它!

为了避免我使用的编译错误

let name1:string = person.name || '';

然后验证空字符串。

现在,您可以使用这里的非空断言运算符,它完全用于您的用例。

它告诉TypeScript,即使某些东西看起来可能是null,它也可以相信你它不是:

let name1:string = person.name!;
//                            ^ note the exclamation mark here

我知道这有点晚了,但是除了亚尼克的回答之外使用!的另一种方法是将它转换为字符串,从而告诉TypeScript: 我确定这是一个字符串,从而转换它。

let name1:string = person.name;//<<<Error here

let name1:string = person.name as string;

这将使错误消失,但如果这是不是字符串,你将得到一个运行时错误…这也是我们使用TypeScript来确保类型匹配并避免在编译时中出现此类错误的原因之一。

你试图设置变量name1,女巫类型设置为严格的字符串(它必须是字符串),值从对象字段name,女巫值类型设置为可选字符串(它可以是字符串或未定义,因为问题符号)。如果你真的需要这个行为,你必须像这样改变name1的类型:

let name1: string | undefined = person.name;

一切都会好的;

这里有一个快速的方法来了解正在发生的事情:

当你做以下事情时:

的名字吗?:字符串

你对TypeScript说它是可选的。然而,当你这样做的时候:

let name1 : string = person.name; //<<<Error here

你没有给它选择的余地。你需要在它上面有一个反映未定义类型的联合:

let name1 : string | undefined = person.name; //<<<No error here

使用您的回答,我能够概述以下内容,基本上是一个接口,一个类和一个对象。我发现这种方法更简单,如果你不这样做也没关系。

// Interface
interface iPerson {
fname? : string,
age? : number,
gender? : string,
occupation? : string,
get_person?: any
}


// Class Object
class Person implements iPerson {
fname? : string;
age? : number;
gender? : string;
occupation? : string;
get_person?: any = function () {
return this.fname;
}
}


// Object literal
const person1 : Person = {
fname : 'Steve',
age : 8,
gender : 'Male',
occupation : 'IT'
}


const p_name: string | undefined = person1.fname;


// Object instance
const person2: Person = new Person();
person2.fname = 'Steve';
person2.age = 8;
person2.gender = 'Male';
person2.occupation = 'IT';


// Accessing the object literal (person1) and instance (person2)
console.log('person1 : ', p_name);
console.log('person2 : ', person2.get_person());

从TypeScript 3.7开始,你可以使用空合并运算符 ??。您可以将此特性视为在处理null或未定义时“退回”到默认值的一种方式

let name1:string = person.name ?? '';

当试图使用默认值时,??操作符可以替换||的使用,并且可以在处理不能使用||的布尔值、数字等时使用。

从TypeScript 4开始,你可以使用??=赋值操作符作为a ??= b,这是a = a ?? b;的替代

你可以使用NonNullable实用程序类型:

例子

type T0 = NonNullable<string | number | undefined>;  // string | number
type T1 = NonNullable<string[] | null | undefined>;  // string[]

文档

更适合生产环境的处理方法是实际确保存在name。假设这是一个有一群人参与的大型项目的最小示例,你不知道getPerson在未来将如何变化。

if (!person.name) {
throw new Error("Unexpected error: Missing name");
}


let name1: string = person.name;

或者,你可以将name1输入为string | undefined,并进一步处理undefined的情况。但是,最好尽早处理意外错误。

你也可以让TypeScript通过省略显式类型来推断类型:let name1 = person.name这仍然可以防止name1被重新分配为一个数字。

如果你想拥有nullable属性,将你的接口更改为:

interface Person {
name?:string | null,
age?:string | null,
gender?:string | null,
occupation?:string | null,
}

如果未定义不是这种情况,可以从属性名前面删除问号(?)。

如果你从你的getPerson函数中移除<Person>强制转换,那么TypeScript将足够智能地检测到你返回的对象肯定具有name属性。

所以只要转一下:

interface Person {
name?: string,
age?: string,
gender?: string,
occupation?: string,
}


function getPerson() {
let person = <Person>{name: 'John'};
return person;
}


let person: Person = getPerson();
let name1: string = person.name;

成:

interface Person {
name?: string,
age?: string,
gender?: string,
occupation?: string,
}


function getPerson() {
let person = {name: 'John'};
return person;
}


let person = getPerson();
let name1: string = person.name;

如果不能这样做,则必须使用“明确赋值断言操作符”;正如@yannick1976所建议的:

let name1: string = person.name!;
根据你的定义,Person.name可以为空,但name1不能。 有两种情况:

Person.name永不为空

通过使用!告诉编译器你确定该名称不是空的

let name1: string = person.name!;

Person.name可以为空

在case name为null时指定一个默认值

let name1: string = person.name ?? "default name";

你可以这样做!

let name1:string = `${person.name}`;

但是记住name1可以是空字符串

  @Input()employee!:string ;`enter code here`
announced:boolean=false;
confirmed:boolean=false;
task:string="<topshiriq yo'q>";


constructor(private taskService:TaskService ) {
taskService.taskAnnon$.subscribe(
task => {
this.task=task;
this.announced=true;
this.confirmed=false;
}
)
}


ngOnInit(): void {
}
confirm(){
this.confirmed=true
this.taskService.confirimTask(this.employee);`enter code here`
}
}

这是我发现的检查属性是否未定义而不生成警告的唯一解决方案

type NotUndefined<T, K extends keyof T> = T & Record<K, Exclude<T[K], undefined>>;
function checkIfKeyIsDefined<T, K extends keyof T>(item: T, key: K): item is NotUndefined<T, K> {
return typeof item === 'object' && item !== null && typeof item[key] !== 'undefined';
}

用法:


interface Listing {
order?: string
...
}
obj = {..., order: 'pizza'} as Listing
if(checkIfKeyIsDefined(item: obj, 'order')) {
order.toUpperCase() //no undefined warning O.O
}

原始回答

我认为使用Karol Majewski提到的Require是相当不错的。另一种实现相同的方法是使用交集类型(实际上由Require在内部使用)

function getPerson(): Person & {name: string} {
const person = {name:"John"};
return person;
}


const person = getPerson();
const name1: string = person.name;

使用Require或交集类型的优点是,我们不会像非空断言操作符那样推翻typescript编译器。