Análise estática com Flow — parte 3

Leandro Nunes
Nov 7, 2017 · 4 min read
Image for post
Image for post

Na segunda parte da série, vimos como integrar o Flow com o editor e um setup mínimo para manter a qualidade do código gerado através de indicadores de cobertura.

Caso seja seu primeiro contato com esta série, veja a primeira parte onde mostro como instalar e configurar o Flow.

Agora que já temos o workflow definido, vamos focar em algumas features que o Flow nos oferece a nível de sintaxe do código.

Como você já deve ter percebido nos exemplos anteriores, facilmente conseguimos deixar nosso código fortemente tipado e o Flow irá fazer a análise e nos mostrar os problemas em tempo real.

const foo:number = 'bar'
^ string. This type is incompatible with number

Porém, caso você não queira deixar todo seu código fortemente tipado por algum motivo, o Flow oferece uma análise de código através da inferência de tipos e consegue detectar possíveis erros que seriam gerados em tempo de execução, por exemplo:

const double = val => val * 2console.log(double(2)) // 4
console.log(double('foo'))
^ string. The operand of an arithmetic operation
must be a number.

Perceba que ele conseguiu analisar que a função double executa uma operação matemática e ao notar que seria executado uma chamada passando uma string como parâmetro ao invés de número, essa operação não seria possível e isso iria gerar um erro na aplicação durante sua execução. Toda essa análise estática foi feita mesmo sem o tipo estar fortemente definido no parâmetro da função double.

Tipos primitivos

Por dedução, os tipos primitivos ficam fáceis de serem declarados mesmo sem olhar a documentação, certo ?

const num:number = 1
const str:string = 'foo'
const bool:boolean = true

E null e undefined, como ficam ?

const nil:null = null
const undef:void = undefined

Funções

Nas funções podemos declarar tipo tanto nos parâmetros que está recebendo, quanto no seu retorno:

// ES6
const sum = (val1:number, val2:number):number => val1 + val2
// ES5
function sum(val1:number, val2:number):number {
return val1 + val2
}

Arrays

podemos declarar de duas formas:

const arr:Array<number> = [1, 2, 3]
const arr:Array<string> = ['foo', 'bar']
// ou
const arr:number[] = [1, 2, 3]
const arr:string[] = ['foo', 'bar']

Caso seu Array possa receber dois tipos de valores mesclados, se declarado da forma acima, irá receber o seguinte erro:

const arr:Array<number> = ['foo', 1]
^ array literal. Has some incompatible type argument with array type Type argument `T` is incompatible:

Para estes caso, podemos declarar aceitando um tipo ou outro:

const arr:Array<string|number> = ['foo', 'bar', 1, 2, 3]
const arr:(string|number)[] = ['foo', 'bar', 1, 2, 3]
const arr:(string|number|boolean)[] = ['foo', 123, true]

Um outro detalhe que podemos fazer com a declaração de Array é definir o tipo de cada valor baseado na sua posição, dessa forma o Array irá respeitar o tamanho e o tipo definido. Isso é chamado de Tuplas.
Por exemplo:

const arr:[string, string, number] = ['foo', 'bar', 123]const arr:[string, string, number] = ['foo', 'bar']
^ array literal. Tuple arity mismatch. This tuple has 2 elements and cannot flow to the 3 elements of tuple type

Apenas para conhecimento: Existe um tipo chamado “any” que aceita qualquer tipo de valor, porém este deve ser utilizado somente em último caso, pois irá ignorar qualquer análise de tipo.

Objetos

Podemos declarar de forma genérica:

const obj:Object = {}
const obj:Object = {str: 'foo'}

Como também podemos declarar com uma espécie de “schema” onde cada propriedade deverá ser respeitada:

const obj:{str:string, num:number} = {str: 'foo', num: 123}

Caso o schema não seja respeitado, um erro será gerado:

const obj:{str:string, num:number} = {str: 'foo'}
^ object literal. This type is incompatible with object type

Caso você deseja que alguma propriedade seja opcional (pode existir ou não), e seja validada apenas quando existir, basta adicionar “?” após o nome da propriedade:

// OK
const obj:{str:string, num?:number} = {str: 'foo'}
const obj:{str:string, num?:number} = {str: 'foo', num: undefined}
const obj:{str:string, num?:number|null} = {str: 'foo', num: null}
// NOK
const obj:{str:string, num?:number} = {str: 'foo', num: null}

É aí que você deve estar querendo me interromper e perguntar:

- Humm, bem legal isso! Mas teria alguma forma de ficar mais legível e reaproveitável meu código, de forma que eu consiga definir schemas customizados dos meus objetos e declará-los de forma que o Flow valide para mim as atribuições automaticamente ?

Muito bem pequeno gafanhoto! Eu sabia que você iria pensar nisso e preparei um exemplo. Isso o Flow chama de Alias:

// Definição do alias
type MyObject = {
str: string,
num: number
};
// Atribuindo o alias à variável desejada
const myObj:MyObject = {
str: 'bar',
num: 123,
}

Um conceito importante é que o Flow entende que um objeto tipado, passa a ter suas propriedades “seladas”, ou seja:

const myObj:MyObject = {
str: 'bar'
}
myObj.num = 123 // funciona
myObj.newProp = 'foo bar' // não funciona
^ property `newProp`. Property not found in object type

Isso não funciona, pois quando tentamos atribuir “newProp” ao objeto, o flow verifica no Schema que esta propriedade não foi declarada e como ele trata os objetos de forma selada, nenhuma nova propriedade pode ser adicionada.

Porém observe que, se fizermos isso no momento da atribuição, irá funcionar:

const myObj:MyObject = {
str: 'bar',
num: 123,
newProp: 'intruso'
}

Então caso queiramos forçar exatamente e somente as propriedades que definirmos, precisamos declarar o schema adicionando “|” :

// Definição do alias
type MyObject = {|
str: string,
num: number
|};
const myObj:MyObject = {
str: 'bar',
num: 123,
newProp: 'intruso'
^ property `newProp`. Property not found in object type

}

Está gostando da série ?

Clap, compartilhe, comente!

Feedback

Encontrou algum erro, sentiu falta de alguma explicação ou gostaria de ver algum exemplo que ainda não foi abordado, comente!

Meninunes

Web Development by — Leandro “Little Big” Nunes

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store