Created
January 21, 2019 13:17
-
-
Save danirod/5d143d775907e754a42c2d3bd8536756 to your computer and use it in GitHub Desktop.
Algo que he aprendido hoy sobre tipos en TypeScript.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/********************************************************** | |
* COSAS SIMPLES CON TIPOS PARA IR ABRIENDO BOCA. | |
*********************************************************/ | |
/* Una interfaz que maneja datos en una agenda de contactos. */ | |
interface Person { | |
/* Datos personales sobre esta persona. */ | |
name: string; | |
age: number; | |
city: string; | |
/* Datos de la empresa para la que trabaja. */ | |
position: string; | |
company: string; | |
mail: string; | |
}; | |
/* Una instancia de un objeto persona. */ | |
const alex: Person = { | |
name: 'Alex', | |
age: 28, | |
city: 'Madrid', | |
position: 'Developer', | |
company: 'Contosso', | |
mail: '[email protected]', | |
}; | |
/* Comprobamos que se corresponde. */ | |
function printPerson(p: Person) { | |
console.log(`${p.name} tiene ${p.age} años y vive en ${p.city}`); | |
console.log(`Trabaja como ${p.position} en ${p.company} y su mail es ${p.mail}`); | |
} | |
printPerson(alex); | |
/*********************************************************** | |
* TIPO AVANZADO DE TYPESCRIPT PICK | |
**********************************************************/ | |
/* Pick te retorna un subconjunto de una interfaz con las claves que le digas. */ | |
type WorkInfo = Pick<Person, 'position' | 'company' | 'mail'>; | |
function printWorkInfo(p: WorkInfo) { | |
/* Fijate que si descomentas la siguiente línea da error, porque p es un objeto | |
que solo tiene "position", "company" y "mail" como propiedades válidas. */ | |
// console.log(`${p.name} tiene ${p.age} años y vive en ${p.city}`); | |
console.log(`Trabaja como ${p.position} en ${p.company} y su mail es ${p.mail}`); | |
} | |
printWorkInfo(alex); | |
/************************************************************ | |
* TIPO AVANZADO DE TYPESCRIPT KEYOF | |
************************************************************/ | |
/* Dado un tipo T, keyof(T) expande a un tipo discriminante cuyo valor puede ser cualquiera | |
de las claves presentes en T. Por supuesto, para esto T tiene que ser un tipo con keys. | |
En el siguiente ejemplo, PersonKey es de tipo "name" | "age" ... */ | |
type PersonKey = keyof Person; | |
/* Por ejemplo: */ | |
const nameKey: PersonKey = "name"; | |
/* En cambio si descomentas lo siguiente te dará error. */ | |
// const unexistentKey: PersonKey = "hello"; | |
/* Descomenta la siguiente línea y trata de autocompletar tras el =, verás los valores que acepta. */ | |
// const fooKey: PersonKey = | |
/************************************************************* | |
* TIPO AVANZADO DE TYPESCRIPT EXCLUDE | |
*************************************************************/ | |
/* Exclude<U, V> devuelve un tipo discriminado que a su vez es diferencia de tipos. Es decir, | |
Exclude<U, V> puede adoptar cualquiera de los tipos que hay en el tipo discriminado U, | |
excepto aquellos tipos que también estén en V. */ | |
type Vocal = 'a' | 'e' | 'i' | 'o' | 'u'; | |
type PrimeraLetra = 'a' | 'b' | 'c' | 'd' | 'e'; | |
/* Debería quedar claro a estas alturas: */ | |
const vocal: Vocal = 'a'; | |
const primeraLetra: PrimeraLetra = 'c'; | |
/* PrimeraLetraNoVocal será la diferencia de ('a' 'b' 'c' 'd' 'e' - 'a' 'e' 'i' 'o' 'u'). | |
Así que puede adoptar los valores 'b' 'c' 'd'. No puede aceptar 'a' ni 'e'. */ | |
type PrimeraLetraNoVocal = Exclude<PrimeraLetra, Vocal>; | |
const aceptable: PrimeraLetraNoVocal = 'b'; | |
// const inaceptable: PrimeraLetraNoVocal = 'e'; | |
/******************************************************************* | |
* COMBINAMOS KEYOF Y EXCLUDE | |
*******************************************************************/ | |
/* Si combinamos keyof con Exclude, podríamos obtener las keys de una interfaz T | |
excepto aquellas que estén en una lista negra de keys que no queramos devolver. */ | |
type PersonalKeys = Exclude<keyof Person, "company" | "position" | "mail">; | |
/* Fijate que ahora PersonalKeys puede ser 'name', 'age' o 'city'. De momento strings: */ | |
const personalProp: PersonalKeys = "age"; | |
// const unacceptablePersonalProp: PersonalKeys = "company"; | |
/* Si ahora lo juntamos con el Pick que hicimos arriba... */ | |
type PersonalKeys2 = Exclude<keyof Person, keyof WorkInfo>; | |
/* En teoría debería ser equivalente. */ | |
const personalProp2: PersonalKeys2 = "age"; | |
/* Y ya si lo metemos en un Pick, ¡podemos obtener un subobjeto de otro! */ | |
type PersonalPersonData = Pick<Person, Exclude<keyof Person, keyof WorkInfo>>; | |
function printPersonalData(p: PersonalPersonData) { | |
console.log(`${p.name} tiene ${p.age} años y vive en ${p.city}`); | |
// console.log(`Trabaja como ${p.position} en ${p.company} y su mail es ${p.mail}`); | |
} | |
printPersonalData(alex); | |
/* Generalizando podemos hacer un tipo Blacklist. */ | |
type Difference<A, B> = Pick<A, Exclude<keyof A, keyof B>>; | |
function printPersonalDataUsingDiff(p: Difference<Person, WorkInfo>) { | |
console.log(`${p.name} tiene ${p.age} años y vive en ${p.city}`); | |
// console.log(`Trabaja como ${p.position} en ${p.company} y su mail es ${p.mail}`); | |
} | |
printPersonalDataUsingDiff(alex); | |
/* Hasta aquí mi charla Ted, gracias por venir. */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
increible