Texto tipográfico: Digite 'string | undefined 'não pode ser atribuído ao tipo' string '


113

Quando torno opcional qualquer propriedade de uma interface, recebo um erro como seguir ao atribuir seu membro a alguma outra variável

TS2322: Digite 'string | undefined 'não pode ser atribuído ao tipo' string '. O tipo 'undefined' não pode ser atribuído ao tipo '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 

Como posso contornar esse erro?

Respostas:


225

Agora você pode usar o operador de asserção não nulo que está aqui exatamente para o seu caso de uso.

Ele diz ao TypeScript que mesmo que algo pareça nulo, ele pode confiar em você que não é:

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

4
Isso é exatamente o que eu estava procurando!
— Shautieh

1
Até que ESLint não restrinja o uso de operador de asserção não nulo :)
— Anatoly

4
Estou chocado que tal coisa precise existir. 🤯
— GONeale

23
Este é um conselho terrível! Em vez disso, ajude o compilador a descobrir isso. Adicione uma marca antes de acessar a propriedade, onde você pode lançar ou retornar se o nome não estiver definido.
— geon

2
Discordo desses dois últimos comentários ... Por exemplo, estou renderizando condicionalmente um elemento visual se a propriedade existir, e anexada a esse elemento está uma função que usa a propriedade. Uma verificação extra não nula para a propriedade dentro da função é desnecessária
— eazy_g

61

Para evitar o erro de compilação que usei

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

E então valide a string vazia.


1
E se não for uma string, mas um objeto?
— Anatoly

2
Se for um objeto, em vez de '' será {}
— Kriti,

Isso é algo que você pode fazer quando está encadeando valores e obtém esse tipo de erroOptional chain expressions can return undefined by design - using a non-null assertion is unsafe and wrong.
— tHeSiD

30

Eu sei que esta é uma resposta meio atrasada, mas outra maneira além da resposta de yannick https://stackoverflow.com/a/57062363/6603342 de usar! é convertê-lo como string, dizendo ao TypeScript que tenho certeza de que é uma string convertendo

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

para

let name1:string = person.name as string;

Isso fará com que o erro desapareça, mas se por acaso não for uma string, você obterá um erro em tempo de execução que é uma das reassons que estamos usando o TypeScript para garantir que o tipo corresponda e evitar tais erros no tempo de compilação .


1
Isso pode fazer com que o erro desapareça, mas nunca altera o tipo real da variável.
— Mansi

Sinto muito, mas acho que você está muito enganado, como mencionei, isso na verdade mudará o tipo, pois lançará uma exceção de tempo de execução se o tipo não for uma string ou não tiver um método toString. Isso irá converter tudo o que estiver lá em uma string, ou seja, você tem um número que tentará chamar a função .toString de tudo o que você tiver lá.
— Harry

2
Mas esse não será o caminho correto, digamos que se meu nome tiver o número "0", ele apenas converterá em string ... Em vez disso, ele deve gerar um erro e dizer um nome inválido. Pessoalmente, eu não usaria esse typecast e, especialmente, verificaria o tipo passado no objeto .. mas todos nós temos estilos de codificação diferentes, abertos para mais discussão sobre o mesmo
— Mansi

Sim, mas isso está completamente fora do contexto da pergunta que essa resposta foi dada. Não sabemos se este é um formulário se não houver etapas para filtrar isso de antemão. Além disso, o que você está sugerindo que seria impossível nessa fase sem algumas soluções alternativas realmente sujas.
— Harry

1
Não há necessidade de soluções alternativas, apenas uma verificação antes de tentar acessar a variável. Ambos os casos seriam tratados facilmente, os erros desapareceriam e seu código estaria mais seguro. Experimente :)
— Mansi

27

A partir do TypeScript 3.7, você pode usar o operador de coalescência nula ?? . Você pode pensar neste recurso como uma forma de "retroceder" para um valor padrão ao lidar com nulo ou indefinido

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

O ??operador pode substituir os usos de ||ao tentar usar um valor padrão e pode ser usado ao lidar com booleanos, números, etc. onde ||não pode ser usado.

A partir do TypeScript 4, você pode usar o ??=operador de atribuição, a ??= bque é uma alternativa paraa = a ?? b;


8

Uma maneira mais pronta para a produção de lidar com isso é garantir que nameesteja presente. Supondo que este seja um exemplo mínimo de um projeto maior no qual um grupo de pessoas está envolvido, você não sabe como getPersonisso mudará no futuro.

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

let name1: string = person.name;

Como alternativa, você pode digitar name1como string | undefinede lidar com casos undefinedmais abaixo. No entanto, normalmente é melhor lidar com erros inesperados mais cedo.

Você também pode permitir que o TypeScript inferir o tipo, omitindo o tipo explícito: let name1 = person.nameisso ainda impedirá que name1seja reatribuído como um número, por exemplo.


7

tente descobrir qual é o valor real de antemão. Se persontiver um válido name, atribua-o a name1, do contrário atribua undefined.

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

2
hmmm. Isso seria muito prolixo se eu quiser fazer várias atribuições. Existe uma maneira de desativar este aviso específico?
— asdasd de

infelizmente, não, exceto se você tornar nameobrigatório, removendo o ponto de interrogação.
— Lynx 242

PS: Qual versão do TypeScript você usa? Eu uso 3.2.4 e não encontro esta Mensagem. Em minha classe de teste, o código compila perfeitamente.
— Lynx 242

mesma versão. Recebo este erro no webstorm, mas não no vscode
— asdasd

Isso é estranho, porque eu uso IntelliJ, que supostamente é semelhante ao WebStorm quando se trata de aplicação de regras do TS ?!
— Lynx 242

4

Esta é uma maneira rápida de saber o que está acontecendo:

Quando você fez o seguinte:

nome? : corda

Você estava dizendo para o TypeScript que era opcional. No entanto, quando você fez:

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

Você não deixou uma escolha. Você precisava ter uma união refletindo o tipo indefinido:

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

Usando sua resposta, consegui esboçar o seguinte, que é basicamente uma Interface, uma Classe e um Objeto. Acho essa abordagem mais simples, não importa se você não fizer isso.

// 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());

2

Você está tentando definir uma variável name1, tipo de bruxa definido como string estrita (DEVE ser string) com valor do campo de objeto name, tipo de valor de bruxa definido como string opcional (pode ser string ou indefinido, por causa do sinal de interrogação). Se você realmente precisa desse comportamento, você deve alterar o tipo name1assim:

let name1: string | undefined = person.name;

E vai ficar tudo bem;


0

Você pode usar o NonNullabletipo de utilitário:

Exemplo

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

Docs .



-1

Solução 1: remover a definição de tipo explícita

Como getPersonjá retorna um Personcom um nome, podemos usar o tipo inferido.

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

let person = getPerson();

Se tivéssemos que definir person: Person, perderíamos uma informação. Sabemos que getPersonretorna um objeto com uma propriedade não opcional chamada name, mas descrevê-lo como Persontraria a opcionalidade de volta.

Solução 2: use uma definição mais precisa

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;

Solução 3: redesenhar sua interface

Uma forma em que todas as propriedades são opcionais é chamada de tipo fraco e geralmente é um indicador de projeto ruim. Se fôssemos fazername uma propriedade obrigatória, seu problema desapareceria.

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

-14

Tive o mesmo problema.

Eu descobrir que reagem-scrips adicionar "strict": truea tsconfig.json.

Depois de removê-lo, tudo funcionou bem.

Editar

É preciso avisar que alterar essa propriedade significa que você:

não sendo mais avisado sobre possíveis erros de tempo de execução.

como apontado por PaulG nos comentários! Obrigado :)

Use "strict": falsesomente se você entender completamente o que isso afeta!


9
Isso pode 'funcionar'. Mas só funciona no sentido de que você não está mais sendo avisado sobre possíveis erros de tempo de execução. Eu encorajaria a pesquisa sobre o que a verificação estrita em Typescript faz: medium.com/webhint/going-strict-with-typescript-be3f3f7e3295
— PaulG

5
Devo mencionar que o OP perguntou: "Como faço para contornar este erro?" não, "Como faço para corrigir esse problema?"
— devinbost de

Simplesmente adicionar name: string = undefined (como recomendado por pacotes como json2typescript) irá gerar o erro 2322, a menos que você desative o estrito, que é o que a maioria das pessoas precisa fazer. Essa resposta aceita é clara, correta e merece muito mais votos.
— AUSTX_RJL
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.