What's New in Typescript 3.0

  • 2018-08-15 04:55 AM
  • 446

TypeScript 3.0 adds support to multiple new capabilities to interact with function .... TypeScript 3.0 introduces a new top type unknown

Typescript 3 is out! The team added some cool new features which include:

  • Tuples in rest parameters and spread expressions
  • The unknown type
  • Support for defaultProps in JSX

We'll look into these features and highlight the functionality they add onto Typescript. Let's get started!

Get Free 15 Geekhttps://my.geekcash.io/ref/5b3c4924d38b6158ce04633f
Free trading fees in the first yearhttps://aiodex.com/?ref=5b45a599c7165734d36bb3fc
How to Install Masternode for Geek Cashhttps://codequs.com/p/HyZO2Elg7

Tuples in rest parameters and spread expressions

What is a tuple? It is a data structure that allows us to express an array where the type of a fixed number of elements is known. The types of these elements does not need to be the same.

Table of Contents

  1. Tuples in rest parameters and spread expressions
  2. The unknown type
  3. Support for defaultProps in JSX
  4. Conclusion

There are a number of new fun ways we can interact with function parameter lists as tuples. This in turn allows us to strongly type higher order functions which transform functions and their parameter lists.

Rest parameters with tuples

We can have a tuple type in a rest parameter. In which case:

declare function foo(...args: [string, number, boolean]): void;

is equivalent to:

declare function foo(args_0: string, args_1: number, args_2: boolean): void;

Spread expressions with tuples

We can have a function call with a spread expression of a tuple type as the last argument.

const args: [string, number, boolean] = ["banana", 2, true];
bar(...args);

The bar function call is equivalent to:

bar(arg[0], arg[1], arg[2]);
bar(["banana", 2, true]);

Generic rest parameters

We now can have generic rest parameters, and have these generics be inferred as tuple types.

declare function bind<Q, R extends any[], S>(f: (x: Q, ...args: R) => S, x: S): (...args: R) => S;

So we can have the ...args rest parameter R extend an array and Typescript will extract the parameter list from whatever we pass into f and turn that into a tuple:

declare function f3(x: number, y: string, z: boolean): void;

const f2 = bind(f3, 2);  // (y: string, z: boolean) => void
const f1 = bind(f2, "banana");  // (z: boolean) => void
const f0 = bind(f1, true);  // () => void

f3(2, "banana", true);
f2("banana", true);
f1(true);
f0();

f2, type inference infers:

  • Q: number
  • R: [string, boolean]
  • S: void

For R the tuple type is inferred from sequence of parameters and then expanded to a parameter list.

This particular capability allows for higher-order spreading and declaration of partial parameter lists.

Optional elements

We can append a ? to a tuple type to indicate that it is optional. Therefore we can have this:

let x: [number, string?, boolean?];
x = [2, "banana", true];
x = [2, "banana"];
x = [2];

The length of a tuple type with optional elements is a union of literal types representing all the possible lengths. The length of, let x: [number, string?, boolean?] would be; 1 | 2 | 3.

Rest elements

Another element of a tuple type is a rest element ...Q , with Q being an array type. This rest element means that we may have zero or more elements of the array element type.

For example: [number, ...string[]] : is a tuple with a number element then a number of string elements.

The length of the tuple is not known, the type of the length property is just a number. Lastly when there are no other elements, a rest element in a tuple is identical to itself and a tuple can be empty:

type Bar = [...string[]]; // Equivalent to `string[]`.
type Foo = []; // empty tuple with length 0

The unknown type

The type unkown is a type safe version of any. any encompasses every value but does not force us to do any type-checking before taking any action on it. With unkown we:

  • can assign any value to unkown (just like with any)
  • cannot do any operations on unkown before defining to a specific type (unlike with any)

Note that unkown is only assignable to itself and any.

For example:

let bar: unknown = 10;

// Since `bar` has type `unknown`, it errors on each of these usages.
bar.x.prop;
bar.y.prop;
bar.z.prop;
bar();
new bar();
upperCase(bar);
bar `hello world!`;

function upperCase(x: string) {
    return x.toUpperCase();
}

If we used type assertion however we can by pass this:

let bar: unknown = 10;

// type-guard
function checkTypes(obj: any): obj is { x: any, y: any, z: any } {
    return !!obj &&
        typeof obj === "object" &&
        "x" in obj &&
        "y" in obj &&
        "z" in obj;
}

if (checkTypes(bar)) {
    // now we&apos;re allowed to access certain properties again.
    bar.x.prop;
    bar.y.prop;
    bar.z.prop;
}

// We use a type assertion here
upperCase(bar as string);

function upperCase(x: string) {
    return x.toUpperCase();
}

Support for defaultProps in JSX

Before, in Typescript we could not make React defaultProps declarations inside JSX components. So we'd have to declare properties optional and use non-null assertions inside of render:

export interface Props { name?: string }
export class Greetings extends React.Component<Props> {
    render() {
        const { name } = this.props;

        return <div>Hello ${name!.toUpperCase()}!</div>;
    }
    static defaultProps = { name: "world"}
}

Now, we have a new helper type LibraryManagedAttributes which tells Typescript what attributes a JSX tag accepts. Which enables us to do this:

export interface Props {
    name: string
}

export class Greetings extends React.Component<Props> {
    render() {
        const { name } = this.props;
        return <div>Hello ${name.toUpperCase()}!</div>;
    }
    static defaultProps = { name: "world"}
}

// no type assertions needed
let el = <Greetings />

However there are some limitations with this new support:

For defaultProps that explicitly specify their type, for example, static defaultProps: Partial<Props>, or stateless function components (SFCs) whose defaultProps are declared with Partial<Props>, the Typescript compiler will not be able to tell which properties have defaults because defaultProps includes all the properties of props.

To evade this we can use static defaultProps: Pick<Props, "name">; as an explicit type annotation OR do not add a type annotation like in the example we have.

For SFCs we can use ES2015 default initializers:

function Greetings({ name = "world" }: Props) {
    return <div>Hello ${name.toUpperCase()}!</div>;
}

Conclusion

That is the gist on the new features in Typescript 3.0. Hopefully this article got you pumped to learn more. If you want to learn more on the inner workings of the new features you can look at the release notes by the Typescript team thats really insightful. This article on the Microsoft blog explains a bit further on how to use these features.

Enjoy!

Learn More

Understanding TypeScript

Learn TypeScript From Scratch

TypeScript For Absolute Beginners - Make Typescript App

Angular 6 (formerly Angular 2) - The Complete Guide

The Complete JavaScript Course 2018: Build Real Projects!

The Web Developer Bootcamp

Suggest