打字稿:Type'string undefined'不可分配给'string'类型

时间:2019-02-02 18:51:08

标签: typescript

当我作出接口可选的任何属性,我喜欢而分配其成员的一些其它可变以下的错误

  

TS2322:键入“字符串” |未定义''不能分配给``字符串''类型。类型'undefined'不能分配给类型'string'。

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 

如何解决此错误?

17 个答案:

答案 0 :(得分:24)

从TypeScript 3.7开始,您可以使用无效合并运算符 ??。您可以认为此功能是在处理null或未定义时将其“回退”到默认值的一种方法

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

在尝试使用默认值时,??运算符可以替换||的使用,并且在不能使用||的布尔值,数字等情况下也可以使用。 / p>

从TypeScript 4开始,您可以将??=赋值运算符用作a ??= b,这是a = a ?? b;的替代选择

答案 1 :(得分:5)

一种更易于生产的方式来处理此问题,实际上是确保存在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被重新分配为数字。

答案 2 :(得分:4)

为避免我使用的编译错误

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

然后验证空字符串。

答案 3 :(得分:3)

根据您的定义,Person.name 可以为空,但 name1 不能。 有两种情况:

Person.name 永远不会为空

使用 !

告诉编译器您确定名称不为空
let name1: string = person.name!;

Person.name 可以为空

如果名称为空,请指定默认值

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

答案 4 :(得分:2)

试图找出实际值提前是什么。如果person具有有效的name,请将其分配给name1,否则分配undefined

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

答案 5 :(得分:2)

我知道这是一个较晚的答案,但除了yannick的答案https://stackoverflow.com/a/57062363/6603342之外,还有另一种使用方式!是将其转换为字符串,从而告诉TypeScript我确定这是字符串,因此可以转换

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

let name1:string = person.name as string;

这将使错误消失,但是如果有可能是不是字符串,您将收到运行时错误,这是我们使用TypeScript来确保类型正确的原因之一匹配并避免在编译时出现此类错误

答案 6 :(得分:2)

如果您从 <Person> 函数中删除 getPerson 转换,那么 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!;

答案 7 :(得分:2)

如果您想拥有可为空属性,请将您的界面更改为:

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

如果不是未定义,您可以删除属性名称前面的问号 (?)。

答案 8 :(得分:1)

你可以这样做!

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

但记住 name1 可以是空字符串

答案 9 :(得分:1)

您现在可以使用完全适合您的用例的non null assertion operator

它告诉打字稿,即使某些东西看起来可能为空,也可以相信它不是:

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

答案 10 :(得分:1)

您尝试设置变量name1,将女巫类型设置为严格字符串(必须为字符串),对象字段为name,女巫值类型设置为可选字符串(可以为string或未定义,因为有问号)。如果您确实需要这种行为,则必须像这样更改name1的类型:

let name1: string | undefined = person.name;

没关系;

答案 11 :(得分:0)

解决方案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,
}

答案 12 :(得分:0)

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

示例

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

Docs

答案 13 :(得分:0)

您可以使用Typescript的可选链接。 示例:

const name = person?.name;

如果name对象上存在属性person,则将获得其值,但如果不存在,它将自动返回undefined。

您可以利用此资源更好地理解。

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html

答案 14 :(得分:0)

这是了解正在发生的事情的快速方法:

执行以下操作时:

名字? :字符串

您对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());

答案 15 :(得分:-1)

请注意,如果变量来自数组或解构,则可以提供默认值:

const { DB_HOST = "localhost", DB_PORT: "5432" } = process.env

db.connect(DB_HOST, DB_PORT);
const connectToDb = (host = "localhost", port: "5432") => db.connect(host, port);

答案 16 :(得分:-8)

有同样的问题。

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

删除后,一切正常。