Cuando hago que cualquier propiedad de una interfaz sea opcional, aparece un error como el siguiente al asignar su miembro a alguna otra variable:
TS2322: Type 'string | undefined' is not assignable to type 'string'. Type 'undefined' is not assignable to type '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¿Cómo soluciono este error?
Según su definición, Person.name puede ser nulo pero name1 no. hay dos escenarios:
Person.name nunca es nulo dígale al compilador que está seguro de que el nombre no es nulo usando !
let name1: string = person.name!;Person.name puede ser nuloespecificar un valor predeterminado en caso de que el nombre sea nulo
let name1: string = person.name ?? "default name"; @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` } }si desea tener una propiedad anulable, cambie su interfaz a esto:
interface Person { name?:string | null, age?:string | null, gender?:string | null, occupation?:string | null, }si no está definido, puede eliminar los signos de interrogación (?) delante de los nombres de las propiedades.
Si elimina la conversión <Person> de su función getPerson , TypeScript será lo suficientemente inteligente como para detectar que devuelve un objeto que definitivamente tiene una propiedad de name .
Así que simplemente gire:
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;Dentro:
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;Si no puede hacer eso, entonces tendrá que usar el "operador de aserción de asignación definida" como sugirió @ yannick1976:
let name1: string = person.name!;¡Puedes hacer así!
let name1:string = `${person.name}`; pero recuerda que name1 puede ser una cadena vacía
Esta fue la única solución que encontré para verificar si un atributo no está definido y no genera advertencias.
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'; }uso:
interface Listing { order?: string ... } obj = {..., order: 'pizza'} as Listing if(checkIfKeyIsDefined(item: obj, 'order')) { order.toUpperCase() //no undefined warning OO }respuesta original
Puede utilizar el tipo de utilidad NonNullable :
Ejemplo
type T0 = NonNullable<string | number | undefined>; // string | number type T1 = NonNullable<string[] | null | undefined>; // string[]Una forma más preparada para la producción de manejar esto es asegurarse de que el name esté presente. Suponiendo que este es un ejemplo mínimo de un proyecto más grande en el que está involucrado un grupo de personas, no sabe cómo getPerson en el futuro.
if (!person.name) { throw new Error("Unexpected error: Missing name"); } let name1: string = person.name; Como alternativa, puede escribir name1 como string | undefined y manejar los casos de undefined más abajo. Sin embargo, normalmente es mejor manejar los errores inesperados antes.
También puede dejar que TypeScript deduzca el tipo omitiendo el tipo explícito: let name1 = person.name Esto aún evitará que name1 se reasigne como un número, por ejemplo.
A partir de TypeScript 3.7, ¿puede usar el operador coalescente nulo ?? . Puede pensar en esta función como una forma de "retroceder" a un valor predeterminado cuando se trata de valores nulos o indefinidos.
let name1:string = person.name ?? ''; El ?? el operador puede reemplazar los usos de || cuando se intenta usar un valor predeterminado y se puede usar cuando se trata de valores booleanos, números, etc. donde || No puede ser usado.
A partir de TypeScript 4, puede usar el operador de asignación ??= como a ??= b , que es una alternativa a a = a ?? b;
Está tratando de establecer la variable name1 , el tipo de bruja establecido como una cadena estricta (DEBE ser una cadena) con el valor del name del campo del objeto, el tipo de valor de bruja establecido como una cadena opcional (puede ser una cadena o indefinida, debido al signo de pregunta). Si realmente necesita este comportamiento, debe cambiar el tipo de name1 de esta manera:
let name1: string | undefined = person.name;Y estará bien;
Aquí hay una manera rápida de saber lo que está sucediendo:
Cuando hiciste lo siguiente:
¿nombre? : cuerda
Le decías a TypeScript que era opcional. Sin embargo, cuando lo hiciste:
let name1 : string = person.name; //<<<Error hereNo lo dejaste a elección. Necesitabas tener una Unión reflejando el tipo indefinido:
let name1 : string | undefined = person.name; //<<<No error hereUsando su respuesta, pude esbozar lo siguiente, que es básicamente una interfaz, una clase y un objeto. Encuentro este enfoque más simple, no importa si no lo hace.
// 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());trate de averiguar cuál es el valor real de antemano. Si la person tiene un name válido, asígnelo a name1 , de lo contrario, asigne undefined .
let name1: string = (person.name) ? person.name : undefined;Solución 1: elimine la definición de tipo explícito
Dado que getPerson ya devuelve una Person con un nombre, podemos usar el tipo inferido.
function getPerson(){ let person = {name:"John"}; return person; } let person = getPerson(); Si tuviéramos que definir person: Person perderíamos un dato. Sabemos que getPerson devuelve un objeto con una propiedad no opcional llamada name , pero describirlo como Person recuperaría la opcionalidad.
Solución 2: utilice una definición más 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;Solución 3: rediseñe su interfaz
Una forma en la que todas las propiedades son opcionales se denomina tipo débil y, por lo general, es un indicador de mal diseño. Si tuviéramos que name una propiedad requerida, su problema desaparecería.
interface Person { name:string, age?:string, gender?:string, occupation?:string, }Tenía el mismo problema.
Descubrí que react-scrips agrega "strict": true a tsconfig.json .
Después de quitarlo, todo funciona muy bien.
Editar
Necesito advertir que cambiar esta propiedad significa que usted:
ya no recibir advertencias sobre posibles errores en tiempo de ejecución.
como ha sido señalado por PaulG en los comentarios! Gracias :)
¡Use "strict": false solo si comprende completamente a qué afecta!
Para evitar el error de compilación que usé
let name1:string = person.name || '';Y luego valide la cadena vacía.
Ahora puede usar el operador de aserción no nulo que está aquí exactamente para su caso de uso.
Le dice a TypeScript que, aunque parezca que algo podría ser nulo, puede confiar en que no lo es:
let name1:string = person.name!; // ^ note the exclamation mark hereSé que esto es un poco tarde, ¡pero otra forma además de la respuesta de yannick para usar ! es convertirlo como una cadena, diciéndole a TypeScript: estoy seguro de que esto es una cadena , convirtiéndolo así.
let name1:string = person.name;//<<<Error herepara
let name1:string = person.name as string;Esto hará que el error desaparezca, pero si por casualidad esto no es una cadena , obtendrá un error de tiempo de ejecución... que es una de las razones por las que usamos TypeScript para garantizar que el tipo coincida y evitar tales errores en tiempo de compilación .