Coloque ? depois do nome de um parâmetro para torná-lo opcional. Quem chama pode omiti-lo, e dentro da função o tipo dele inclui undefined.
O TypeScript verifica o número de argumentos, então sem o ? a primeira chamada seria erro de compilação: Expected 2 arguments, but got 1. (TS2554).
Parâmetros opcionais podem ser undefined
Como quem chama pode omiti-lo, o tipo de um parâmetro opcional dentro da função é T | undefined. Com strictNullChecks você precisa tratar o caso undefined antes de usá-lo como T.
Optional chaining (?.) e nullish coalescing (??) são as ferramentas usuais aqui. Quando o valor alternativo é fixo, um parâmetro com valor padrão é mais curto.
Valores padrão de parâmetros
Um valor padrão torna o parâmetro opcional para quem chama e dá a ele um tipo sem undefined dentro da função. O tipo é inferido a partir do padrão, então a anotação muitas vezes é desnecessária.
Quem chama vê a assinatura repeat(text: string, times?: number, separator?: string). Os padrões seguem a regra do JavaScript: valem quando o argumento é undefined, seja omitido ou passado explicitamente, e não quando é null. Uma expressão de padrão pode usar parâmetros anteriores: function range(start: number, end = start + 10).
Regras de ordem dos parâmetros
| Declaração | Compila? | Observações |
|---|---|---|
(a: number, b?: number) | Sim | Parâmetros opcionais ficam por último |
(a?: number, b: number) | Não | TS1016: A required parameter cannot follow an optional parameter. |
(a = 0, b: number) | Sim | Mas quem chama precisa escrever f(undefined, 5) para usar o padrão |
(a: number, ...rest: number[]) | Sim | Um rest parameter sempre vem por último |
(a?: number, ...rest: number[]) | Sim | Opcional antes do rest é permitido |
Um parâmetro com padrão antes de um obrigatório é válido, mas desajeitado. O tipo dele para quem chama vira number | undefined, e ninguém gosta de escrever undefined como marcador. Se você precisa de um parâmetro inicial flexível, use um objeto de opções ou function overloading.
Omitido vs undefined
x?: number e x: number | undefined se parecem e têm o mesmo tipo dentro da função. A diferença é para quem chama: o primeiro pode ser omitido, o segundo precisa ser passado.
Use | undefined para um argumento obrigatório que pode não ter valor, para que todo mundo que chama precise pensar nele. Use ? quando omiti-lo é uma chamada normal. (A mensagem diz mesmo "1 arguments": é o texto do TypeScript.)
Rest parameters
Um rest parameter, ...name: T[], junta qualquer número de argumentos em um array. Ele precisa ser o último parâmetro.
Espalhar um array em parâmetros fixos é mais restrito. Um rest parameter aceita o spread de qualquer number[], mas uma função declarada (a: number, b: number) só aceita o spread de uma tupla, porque o TypeScript precisa saber o tamanho:
function point(x: number, y: number) { return { x, y }; }
const list = [3, 4]; // number[]
point(...list);
// error TS2556: A spread argument must either have a tuple type or be passed to a rest parameter.
const pair = [3, 4] as const; // readonly [3, 4]
point(...pair); // fine
Um rest parameter também pode ter um tipo de tupla, que tipa cada posição: ...args: [name: string, age?: number].
Objetos de opções
Quando uma função tem mais de dois ou três parâmetros opcionais, quem chama perde a noção das posições. Um objeto de opções com padrões dá argumentos nomeados e sem ordem.
O = {} no final torna o objeto inteiro opcional. Sem ele, fetchData("/a") é erro de compilação (Expected 2 arguments, but got 1., TS2554), e em JavaScript puro a mesma chamada lançaria um TypeError em tempo de execução, porque a desestruturação precisa de um objeto de onde ler.
Parâmetros opcionais em tipos de callback
Em um tipo de função, ? significa "quem chama este callback pode não passar isto". Não significa "o callback pode ignorar isto": um callback sempre pode ignorar os parâmetros finais. Então não marque parâmetros de callback como opcionais só para deixar os handlers receberem menos argumentos.
// Too loose: every handler must now cope with index being undefined
type Visit = (item: string, index?: number) => void;
// Right: the caller always passes both; handlers may use only item
type VisitStrict = (item: string, index: number) => void;
const log: VisitStrict = (item) => console.log(item);
Perguntas frequentes
Como tornar um parâmetro opcional no TypeScript?
Coloque um ? depois do nome: function greet(name?: string). Quem chama pode omiti-lo, e dentro da função o tipo dele é string | undefined, então você o verifica antes de usar. Dar um valor padrão ao parâmetro, name = "there", também o torna opcional e remove o undefined dentro da função.
Um parâmetro opcional pode vir antes de um obrigatório no TypeScript?
Não com ?: (a?: number, b: number) gera o erro TS1016, "A required parameter cannot follow an optional parameter." Um parâmetro com valor padrão pode vir primeiro, mas aí quem chama precisa passar undefined explicitamente para usar o padrão, então na prática parâmetros opcionais e com padrão ficam por último.
Qual é a diferença entre x?: number e x: number | undefined?
Dentro da função, os dois são number | undefined. A diferença está na chamada: com x?: number o argumento pode ser omitido, enquanto com x: number | undefined ele precisa ser passado, mesmo que o valor seja undefined. Omiti-lo gera o erro TS2554.
Passar null usa o valor padrão do parâmetro?
Não. O JavaScript aplica um padrão só quando o argumento é undefined (omitido ou passado explicitamente). null é um valor, então é mantido. De qualquer forma, o TypeScript rejeita null para um parâmetro number com strictNullChecks.
Como passar um array como argumentos separados no TypeScript?
Espalhe-o: fn(...args). Para uma função com parâmetros fixos, o array precisa ter um tipo de tupla como [number, number] ou vir de as const; espalhar um number[] gera o erro TS2556, porque o tamanho dele é desconhecido. Espalhar em um rest parameter (...values: number[]) sempre funciona.