L'inférence de type est l'un des points les plus forts et les plus sous-estimés de TypeScript.
Il s'agit ici de déduire implicitement le typage et faire gagner du temps de développement et de refactoring sans perdre en rigueur.
L'idée de TypeScript est en quelque sorte de typer au minimum et de laisser le "transpiler" gérer le reste.
let userName ='Foo';userName =10; // error TS2322: Type '10' is not assignable to type 'string'.
Le type de la variable userName est donc déduit à l'initialisation de la variable et il n'est donc pas nécessaire de la typer explicitement.
Quelques exemples
constgetWeather= (city) => {if (city ==null) {thrownewError(`D'OH!`); }return { rainProbability:0, temperature:30 };};let weather =getWeather('Lyon');// error TS2322: Type '"🔥 Wishtack is cool ! 🔥"' is not assignable// to type '{ rainProbability: number; temperature: number; }'.weather ='🔥 Wishtack is cool ! 🔥';
... ou encore :
constgetWeather= (city) => {if (city ==null) {thrownewError(`D'OH!`); }return { rainProbability:0, temperature:30 };};constgetCityWeather= (city:string) => {constresult=getWeather(city);return {...result, city };};let cityWeather =getCityWeather('Lyon');// error TS2322: Type '"🔥 Wishtack is cool ! 🔥"' is not assignable// to type '{ city: string; rainProbability: number; temperature: number; }'.cityWeather ='🔥 Wishtack is cool ! 🔥';
... au lieu de :
interfaceWeather { rainProbability:number; temperature:number;}constgetWeather= (city:string):Weather=> {if (city ==null) {thrownewError(`D'OH!`); }return { rainProbability:0, temperature:30 };};interfaceCityWeatherextendsWeather { city:string;}constgetCityWeather= (city:string):CityWeather=> {constresult:Weather=getWeather(city);return {...result, city };};let cityWeather:CityWeather=getCityWeather('Lyon');cityWeather ='🔥 Wishtack is hot ! 🔥';
... ou :
constproductList= [ { title:'Browserstack', price:50 }, { title:'Keyboard', price:20 }, { title:'Prerender', price:10 }];let cheapProductsTotalPrice = productList.filter(product =>product.price <25).map(product =>product.price).reduce((total, price) => total + price,0);// error TS2322: Type '"Oups!"' is not assignable to type 'number'.cheapProductsTotalPrice ='Oups!';
Dans le dernier exemple du chapitre sur les interfaces, nous avons implicitement profiter de l'inférence de type.
Toute la puissance de TypeScript repose sur cet art de typer le moins possible mais au bon endroit pour en profiter au maximum.
La signature des fonctions de "callback" que vous attendez est l'un des éléments les plus stratégiques à typer.
interfaceProduct { title:string; price:number;}interfaceProductFilterCallback { (product:Product):boolean}classProductRepository {getMatchingItemList(filter:ProductFilterCallback) { }}constproductRepository=newProductRepository();// error TS2345: Argument of type '(productName: string) => true' is// not assignable to parameter of type 'ProductFilterCallback'.// Types of parameters 'productName' and 'product' are incompatible.// Type 'Product' is not assignable to type 'string'.productRepository.getMatchingItemList((productName:string) => {returntrue;});// error TS2345: Argument of type '(product: Product) => string' is// not assignable to parameter of type 'ProductFilterCallback'productRepository.getMatchingItemList(product => {return'not boolean';});// error TS2339: Property 'name' does not exist on type 'Product'.productRepository.getMatchingItemList(product => {returnproduct.name !=null;});