Skip to content

Instantly share code, notes, and snippets.

@Mefistophell
Last active July 24, 2024 11:38
Show Gist options
  • Save Mefistophell/cd2e5679e1e873ba68babe1004194513 to your computer and use it in GitHub Desktop.
Save Mefistophell/cd2e5679e1e873ba68babe1004194513 to your computer and use it in GitHub Desktop.
Typescript useful features
/**
NoInfer type
*/
function createStreetLight<C extends string>(
colors: C[],
defaultColor?: NoInfer<C>,
) {
// ...
}
createStreetLight(["red", "yellow", "green"], "red"); // OK
createStreetLight(["red", "yellow", "green"], "blue"); // Error
/* ************************************************** */
/**
as const
Works with no types referenced or declared.
We only needed a single const assertion.
*/
function getShapes() {
let result = [
{ kind: "circle", radius: 100 },
{ kind: "square", sideLength: 50 },
] as const;
return result;
}
for (const shape of getShapes()) {
// Narrows perfectly!
if (shape.kind === "circle") {
console.log("Circle radius", shape.radius);
} else {
console.log("Square side length", shape.sideLength);
}
}
type T0 = NonNullable<string | number | undefined>; // string | number
type T0 = ReturnType<() => string>; // string
type T0 = Extract<"a" | "b" | "c", "a" | "f">; // a
/* ************************************************** */
/**
Not-null assertion
Compiled with --strictNullChecks
*/
function validateEntity(e?: Entity) {
// Throw exception if e is null or invalid entity
}
function processEntity(e?: Entity) {
validateEntity(e);
let s = e!.name; // Assert that e is non-null and access name
}
/* ************************************************** */
/**
Object.groupBy and Map.groupBy
*/
const array = [0, 1, 2, 3, 4, 5];
const myObj = Object.groupBy(array, (num, index) => {
return num % 2 === 0 ? "even": "odd";
});
// equivalent to
const myObj = {
even: [0, 2, 4],
odd: [1, 3, 5],
};
const myObj = Map.groupBy(array, (num, index) => {
return num % 2 === 0 ? "even" : "odd";
});
// equivalent to
const myObj = new Map();
myObj.set("even", [0, 2, 4]);
myObj.set("odd", [1, 3, 5]);
/* ************************************************** */
/**
AsyncDisposable and using
Sometimes we have a need to do clean-up after our unit completed its job, this can be: deleting of temp files,
closing network connections, free up some memory.
New keyword `using` applied to a variable gets its Symbol.dispose or Symbol.asyncDispose method
to be called at the end of the scope.
*/
async function doWork() {
// Do fake work for half a second.
await new Promise(resolve => setTimeout(resolve, 500));
}
function loggy(id: string): AsyncDisposable {
console.log(`Constructing ${id}`);
return {
async [Symbol.asyncDispose]() {
console.log(`Disposing (async) ${id}`);
await doWork();
},
}
}
async function func() {
await using a = loggy("a");
await using b = loggy("b");
{
await using c = loggy("c");
await using d = loggy("d");
}
await using e = loggy("e");
return;
}
func();
// Constructing a
// Constructing b
// Constructing c
// Constructing d
// Disposing (async) d
// Disposing (async) c
// Constructing e
// Disposing (async) e
// Disposing (async) b
// Disposing (async) a
/**
DisposableStack and using
useful for doing both one-off clean-up, along with arbitrary amounts of cleanup.
A DisposableStack is a Disposable object that has several methods for keeping track of Disposable objects,
and can be given functions for doing arbitrary clean-up work.
Method defer has a callback that will be called once cleanup is disposed.
Once a resource is created is should be disposed.
*/
function doSomeWork() {
const path = ".some_temp_file";
const file = fs.openSync(path, "w+");
using cleanup = new DisposableStack();
cleanup.defer(() => {
fs.closeSync(file);
fs.unlinkSync(path);
});
// use file...
if (someCondition()) {
// do some more work...
return;
}
// ...
}
/**
Decorator metadata:
Exampe of this is here:
https://gist.github.com/Mefistophell/07d63b44d69d38af9406bc59a35c3ec7
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment