tags : Web Development, Javascript, Programming Languages
Intro stuff
- JS is weakly-typed. So type-coercion can happen
- Primitive coercion:
[@@toPrimitive]("default") → valueOf() → toString()
- Numeric coercion:
[@@toPrimitive]("number") → valueOf() → toString()
- String coercion:
[@@toPrimitive]("string") → toString() → valueOf()
- Primitive coercion:
- TS is a programming language developed by Microsoft.
- Typed superset of Javascript
- Includes its own compiler.
Self realizations (aha moments)
- TS lets you play with types the way you play with values in a general programming language. Eg. You have a type and now you want to extract/transform parts of it into another type.
- This kind of thing you usually do with values but with typescript this is now possible. It’s sort of has a regex feel to types, in-sense what regex makes possible.
- Type functions and Values
type ReturnWhatIPassIn<T> = T;
: This right here is a function that handlestypes
, unlike functions that handlevalues
that I know of in normal Javascript syntax.type ReturnWhatIPassIn = string;
: This right here is a static value of atype
.- So you can basically play with types just the way you play with values
- Just like programming with values, there are multiple ways of getting the same result. Getting better at it will take time and more doing w it.
Primitive types
- All basic types of Javascript
any
: allow anythingunknown
: ensure someone using this type declares what the type isnever
: it’s not possible that this type could happenvoid
: a function which returns undefined or has no return value
Custom types
interface
- Mutable
- Good for behavior, can be
extended
and merged - Can be used for a subset of things, functions, objects etc.
type
- Immutable
- More features than
interface
- Good for data, can be intersected(composed using
|
and&
). - Can be used for everything.
To use types
or interfaces
?
- Use interface until you need to use features from type. This goes the opposite way too.
- Doesn’t really matter which one you go with.
- But some people use type by default too. It boils down to personal preferences and needs.
- My current verdict as of June’23: I’ll go w default
type
, if I need something that needs extending, useinterface
What about namespace
?
Composing types
union
- Basically using
|
- You can’t really declare them, conceptually helpful to think of them like possibilities(multiverse).
- Only
types
can be union’ed notinterfaces
. - We also have discriminated unions, where there’s a common property that distinguishes what’s getting union’ed and then we can later use
typeof
- I think these are like
variants
in Ocaml (See Type Systems)
- I think these are like
generics
- Every function call has 2 argument lists
- Value arguments(runtime) : Parenthesis
()
- Type arguments(typecheck/compile time) : Pointy brackets
<>
- Value arguments(runtime) : Parenthesis
- We can think
generics
as the type arguments, sort of fill-in-the-blanks types. - It allows your type to more dynamic by allowing other types to be part of the original type. Eg. You couldn’t indicate the type of array at all without generics.
Array<string>
is using generics. - Generics in classes and functions are different but use similar syntaxes.
- We do want to constraint the parameter into a generic if we’re doing things specific to the certain type. Usually constraint to generic parameter is added with
extends
. Eg.Poop<T extends string>
- For reverse constraint, you can use
Object
or{}
to match anything butnull
orundefined
Duck type
If it walks like a duck and it quacks like a duck, then it must be a duck.
TS follows duck typing. If the structure is same, you need to explicitly set the type.
interface Point {x: number; y: number;}
function logPoint(p: Point) {console.log(`${p.x}, ${p.y}`);}
const point = { x: 12, y: 26 };
const point2 = { x: 12, y: 26, z: 89 }; // this would work too! needs to be a subset
class VirtualPoint {
x: number;
y: number;
constructor(x: number, y: number) {this.x = x; this.y = y;}
}
const point3 = new VirtualPoint(13, 56);
logPoint(point); // works, but point was never mentioned to be "Point"
logPoint(point2); // works, but point was never mentioned to be "Point"
logPoint(point3); // works, but point was never mentioned to be "Point"
Random things
Levels of TS
- Values exist at the dynamic level.
- Types exist at the static level.
Similarly,
- Normal functions exist at the dynamic level, factories for
values
const valueFactory = (x: number) => x; // definition const myValue = valueFactory(123); // use
- Generic types exist at the static level, factories for
types
type TypeFactory<X> = X; // definition type MyType = TypeFactory<string>; // use
- Working together
function identity<Arg>(arg: Arg): Arg { return arg; } // %inferred-type: number const num1 = identity<number>(123); // %inferred-type: 123 NOTE: It's 123 and not number const num2 = identity(123);
import type
See the following
Do I need to use the import type
Index signatures
- TypeScript index signatures must be either
string
ornumber
(alsosymbols
?)
interface Cache {
[id:string] : string;
}
Type Definitions from where?
To be able to show errors and hints from other packages, the compiler relies on declaration files. Two sources,
- Bundle: check if a library has bundled types, look for an
index.d.ts
file in the project. - DefinitelyTyped: Crowdsourced repo
- Local Declarations: Define it in
declarations.d.ts
maybe
declare
keyword
- declare specifies a type to an already existing variable, not declaring a new one.
- eg. get external js file which has
foo
identifier, tsc doesn’t know about it. So we dodeclare const foo : string
, to tell the compiler that don’t worry aboutfoo
, this is what it looks like it already has a type.
Asserting type
- When you know better exactly what type it would be.
- Only allows type assertions which convert to a more specific or less specific version of a type. (impossible shit not allowed)
const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement; const a = (expr as any) as T; // workaround if ts is too strict
- non-null assertions using
!
in cases where we trying to do something in an optional(?
) property.
Modules in TS
- Any file containing a top-level
import
orexport
is considered a module and is isolated. - Any file without a top-level
import
orexport
is considered as a script whose contents are available in the global scope
Export
- export declarations
- export statements
- re-exports
Import
- importing other modules
- explicit importing of types (guaranteed to be removed from your JavaScript, and tools like Babel can make better assumptions about your code)
Tooling
- The compiler (tsc), way to use it is via
npx tsc
- tsconfig bases: https://github.com/tsconfig/bases
- I like the base/tsconfig repo, but only for CJS configurations. Some mistakes might be there for esm. verify.
- using “moduleResolution”: “node”, but using “node” as the value is telling TypeScript to emit JavaScript that resolves as a CommonJS module.
- what is @types??
Declaration files
.d.ts