What Type<T>[] are you?
Never
Any
Void
Null
Undefined
Unknown
Object
Function
Nil
None
Nada
Nil
Nada
None
Ok some are made up. Sort of.
Scala representation of emptiness
- Nil
- Null
- Nothing
- None
- Unit
We will be exploring the Typescript type system.
But the ideas will be generally applicable to other languages.
Agenda
- Pop Quiz
- Purpose
- What is inheritance?
- Mental model of a type system
Pop Quiz
Can we do this?
anyVar = stringVar;
neverVar = stringVar;
voidVar = unknownVar;
voidVar = undefinedVar;
neverVar = anyVar;
anyVar = neverVar;
stringVar = neverVar;
anyVar = unknownVar;
unknownVar = anyVar;
What do you think?
let stringVar: string = 'string'
let fnVar: Function = () => {};
let objVar: Object = {};
let anyVar: any;
let undefinedVar: undefined;
let nullVar: null = null;
let voidVar: void;
let unknownVar: unknown;
let neverVar: never;
Given these declarations
Can we do these?
Purpose
What is inheritance?
What is inheritance
A mechanism of extending one data type by another data type while retaining parts of the implementation
What is inheritance: example

What is inheritance: more generically

What is inheritance?
interface Animal {
live: boolean
};
interface Cat extends Animal {
meow: void
};
declare const cat: Cat;
cat.live // ok
cat.meow // ok
What is inheritance?
Any variable that is of type `Cat` is-an `Animal`
What is inheritance?
Not every `Animal` though is-a `Cat`
What is inheritance?
Inheritance is one mechanism that enables subtype polymorphism*
What is subtype polymorphism
interface Animal {
live: boolean
};
interface Cat extends Animal {
meow: void
};
const animal: Animal = cat; // ok
const cat: Cat = animal; // not ok
// property 'meow' is missing in type 'animal'
In General

interface Supertype {};
interface Subtype extends Supertype {};
declare const subtype: Subtype;
const supertype: Supertype = subtype; // ok
const subtype: Subtype = supertype; // not ok
The fancy way is to call it Liskov substitution principle
Why is this relevant?
Mental model of a type system
Mental Model: It's actually a tree

Mental Model: It's actually a tree
declare const cat: Cat;
const feline: any = cat // ok because any is a top type
The type at the top of the tree is called a Top Type
In our case, any is a top type

What about the type never?

What is never?
To understand never, consider this:
What should be the return of the following function?
function main() {
while (true) {};
}
function error(message: string) {
throw new Error(message);
}
The function error never actually returns a value
nor does this one
Never is an impossible type. There is no instance of never
Mental Model
Top type: anything can be assigned to it.
Bottom type: it can be assigned to anything.
Never is a bottom type. It can be assigned to anything, but nothing can be assigned to it.
const cat: Cat = neverVar; // ok
const neverVar: never = cat // error
// Cat not assignable to type never

What is the type unknown?

What is Unknown?
Unknown - I don't know, should verify
Any - I don't care
Unknown, unlike Any, forces you to check the type
const notsure: unknown = "a string"; // (1)
notsure.toLowerCase(); // (2) Error: object is of type unknown
if (typeof notsure === "string") {
notsure.toLowerCase(); // ok
}
How were we able to execute step #1?
never - cannot happen
Mental Model

unknown is also a top type
That means, anything can be assigned to unknown; Including any.
But since any is a top most type as well, any can be assigned to unknown.
Top type is a supertype of every other type
How do I assign Any to other values?
cat = animal; // not ok
stringVar = anyVar; // Definitely seen that
If Any is a top type

How do I assign Any?

Any is both top AND bottom type
But not the most bottom type
Never is the bottomest type
anyVar = neverVar // ok
neverVar = anyVar // not ok
So what is Void?
And how is it different from Undefined?

So what is Void?
if undefined is a lack of value
Void is I don't know but it might be nothing

So what is Void?
function foreach(ts, cb) {
for (const t of ts) {
cb(t);
}
}
How should we type this? We don't care about the result of cb and foreach doesn't return anything
function foreach<T>(ts: T[], cb: (t: T) => any): any {
for (const t of ts) {
cb(t);
}
}
Our return is unsafe
function foreach<T>(ts: T[], cb: (t: T) => any): any {
for (const t of ts) {
cb(t).boom(); // uh oh
}
}
And so is our implementation
const apply = foreach([1, 2], (n) => console.log(n));
apply.boom(); // uh oh
So what is Void?
function foreach<T>(ts: T[], cb: (t: T) => undefined): undefined {
for (const t of ts) {
cb(t);
}
}
That won't work either
const ts = [1,2,3];
const empty: number[] = [];
const cb = (t: number) => empty.push(t);
foreach(ts, cb) // Type 'number' is not assignable to type 'undefined'
So what is Void?
function foreach<T>(ts: T[], cb: (t: T) => unknown): unknown {
for (const t of ts) {
cb(t);
}
}
// A function whose declared type is neither 'void' nor 'any' must return a value.
Here Typescript correctly points out you're not actually returning anything even though you promised.
So what is Void?
We need a type to signify an unknown value that may just be nothing.

Unknown - I don't know, should check
Any - I don't care
Never - Can not happen
Void - Not sure, might be nothing

It's complicated
declare const cat: Cat;
const animal: Animal = cat; // ok
declare const cats: Array<Cat>;
const animals: Array<Animal> = cats; // maybe
Is this ok?
If this is ok
Are you my Type[]
By Leon Tager
Are you my Type[]
- 382