¿Cómo declarar un tipo como anulable en TypeScript?

248

Tengo una interfaz en TypeScript.

interface Employee{
    id: number;
    name: string;
    salary: number;
}

Me gustaría hacer salarycomo un campo anulable (como podemos hacer en C #). ¿Es esto posible en TypeScript?

Amitabh
fuente

Respuestas:

276

Todos los campos en JavaScript (y en TypeScript) pueden tener el valor nullo undefined.

Puede hacer que el campo sea opcional, que es diferente de anulable.

interface Employee1 {
    name: string;
    salary: number;
}

var a: Employee1 = { name: 'Bob', salary: 40000 }; // OK
var b: Employee1 = { name: 'Bob' }; // Not OK, you must have 'salary'
var c: Employee1 = { name: 'Bob', salary: undefined }; // OK
var d: Employee1 = { name: null, salary: undefined }; // OK

// OK
class SomeEmployeeA implements Employee1 {
    public name = 'Bob';
    public salary = 40000;
}

// Not OK: Must have 'salary'
class SomeEmployeeB implements Employee1 {
    public name: string;
}

Comparar con:

interface Employee2 {
    name: string;
    salary?: number;
}

var a: Employee2 = { name: 'Bob', salary: 40000 }; // OK
var b: Employee2 = { name: 'Bob' }; // OK
var c: Employee2 = { name: 'Bob', salary: undefined }; // OK
var d: Employee2 = { name: null, salary: 'bob' }; // Not OK, salary must be a number

// OK, but doesn't make too much sense
class SomeEmployeeA implements Employee2 {
    public name = 'Bob';
}
Ryan Cavanaugh
fuente
35
¡Parece que se han implementado tipos estrictamente anulables y estrictos controles nulos y llegarán con Typecript 2.0! (o typescript@nextahora.)
mindplay.dk
¿estás seguro de la var c en el primer ejemplo? Me parece que var b y var c son iguales allí.
martinp999
Para establecer un valor nulo o indefinido sin error de compilación, la opción "estricta" tsconfig debe eliminarse o equivale a "falso""strict" : false
Nicolas Janel
1
Esto es incorrecto. JS distingue entre nulo e indefinido. El código correcto debe ser salary:number|null;Si lo hace salary?:number; salary = null;, obtendrá un error. Sin embargo, salary = undefined;funcionará bien en este caso. Solución: use Union, es decir, '|'
Ankur Nigam
125

El tipo de unión es, en mi opinión, la mejor opción en este caso:

interface Employee{
   id: number;
   name: string;
   salary: number | null;
}

// Both cases are valid
let employe1: Employee = { id: 1, name: 'John', salary: 100 };
let employe2: Employee = { id: 1, name: 'John', salary: null };

EDIT: Para que esto funcione como se esperaba, se debe permitir que el strictNullChecksen tsconfig.

bjaksic
fuente
99
Si usa --strictNullChecks (que debería), esta es una solución válida. No lo usaría a favor de los miembros opcionales, ya que te obliga a agregar un nulo explícito en todos los objetos literales, pero para los valores de retorno de funciones, es el camino a seguir.
Geon
78

Para ser más parecido a C # , defina el Nullabletipo de esta manera:

type Nullable<T> = T | null;

interface Employee{
   id: number;
   name: string;
   salary: Nullable<number>;
}

Prima:

Para hacer que se Nullablecomporte como un tipo de Typecript incorporado, defínalo en un global.d.tsarchivo de definición en la carpeta de origen raíz. Este camino funcionó para mí:/src/global.d.ts

Tim Santeford
fuente
1
Mi respuesta favorita: responde directamente la pregunta sin leerla.
Lqueryvg
1
Usar esto interrumpe la finalización automática de las propiedades del objeto. Por ejemplo si tenemos emp: Partial<Employee>, podemos hacer emp.ido emp.nameetc, pero si tenemos emp: Nullable<Employee>, no podemos haceremp.id
Yousuf Khan
1
Esta es la respuesta real a la pregunta.
Patrick
37

Simplemente agregue un signo de interrogación ?al campo opcional.

interface Employee{
   id: number;
   name: string;
   salary?: number;
}
Miguel Ventura
fuente
54
Como Ryan señaló ...? significa opcional en mecanografiado, no anulable. Sin ? significa que la var debe establecerse en un valor nulo o indefinido. Con ? puedes saltarte toda la declaración.
Él Nrik
3
¡Gracias! Busqué en Google "valor opcional mecanografiado", así que esto es exactamente lo que estaba buscando.
Compañero extraño el
13

Simplemente puede implementar un tipo definido por el usuario como el siguiente:

type Nullable<T> = T | undefined | null;

var foo: Nullable<number> = 10; // ok
var bar: Nullable<number> = true; // type 'true' is not assignable to type 'Nullable<number>'
var baz: Nullable<number> = null; // ok

var arr1: Nullable<Array<number>> = [1,2]; // ok
var obj: Nullable<Object> = {}; // ok

 // Type 'number[]' is not assignable to type 'string[]'. 
 // Type 'number' is not assignable to type 'string'
var arr2: Nullable<Array<string>> = [1,2];
Willem van der Veen
fuente
10
type MyProps = {
  workoutType: string | null;
};
Ritwik
fuente
4

Tuve esta misma pregunta hace un tiempo ... todos los tipos en ts son anulables, porque void es un subtipo de todos los tipos (a diferencia, por ejemplo, scala).

vea si este diagrama de flujo ayuda - https://github.com/bcherny/language-types-comparison#typescript

bcherny
fuente
2
-1: Esto no es cierto en absoluto. En cuanto a voidser 'subtipo de todos los tipos' ( tipo inferior ), consulte este hilo . Además, el gráfico que proporcionó para scala también es incorrecto. Nothingen scala es, de hecho, el tipo de fondo. Typecript, atm, no tiene tipo de fondo mientras que scala .
Daniel Shin
2
"Subtipo de todos los tipos"! = Tipo inferior. Consulte las especificaciones de TS aquí github.com/Microsoft/TypeScript/blob/master/doc/…
bcherny
3

El tipo anulable puede invocar un error de tiempo de ejecución. Así que creo que es bueno usar una opción de compilador --strictNullChecksy declarar number | nullcomo tipo. También en el caso de la función anidada, aunque el tipo de entrada es nulo, el compilador no puede saber qué podría romper, por lo que recomiendo su uso !(signo de exclamación).

function broken(name: string | null): string {
  function postfix(epithet: string) {
    return name.charAt(0) + '.  the ' + epithet; // error, 'name' is possibly null
  }
  name = name || "Bob";
  return postfix("great");
}

function fixed(name: string | null): string {
  function postfix(epithet: string) {
    return name!.charAt(0) + '.  the ' + epithet; // ok
  }
  name = name || "Bob";
  return postfix("great");
}

Referencia. https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-type-assertions

Margaux
fuente