Skip to content

Instantly share code, notes, and snippets.

@danirod
Created January 21, 2019 13:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save danirod/5d143d775907e754a42c2d3bd8536756 to your computer and use it in GitHub Desktop.
Save danirod/5d143d775907e754a42c2d3bd8536756 to your computer and use it in GitHub Desktop.
Algo que he aprendido hoy sobre tipos en TypeScript.
/**********************************************************
* 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: 'alex@contosso.com',
};
/* 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. */
@Sebastiamg
Copy link

increible

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment