3 ms·
> PureScript allows you to remove specific fields from a record type. This feature, is called record subtraction, and it allows more flexibility when transformi
by blue_pants 2y ago
> PureScript allows you to remove specific fields from a record type. This feature, is called record subtraction, and it allows more flexibility when transforming or narrowing down records.
TypeScript does allow you to remove specific fields, if I understand you right [0]:
function removeField<T, K extends keyof T>(obj: T, field: K): Omit<T, K> {
const { [field]: _, ...rest } = obj;
return rest;
}
type Person = { name: string; age: number };
declare const p: Person;
const result = removeField(p, 'age'); // result is of type: Omit<Person, "age">
> PureScript allows you to abstract over rows using higher-kinded types. You can create polymorphic functions that accept any record with a flexible set of fields and can transform or manipulate those fields in various ways. This level of abstraction is not possible in TypeScript.
Again, if I understand you correctly, then TypeScript is able to do fancy manipulations of arbitrary records [1]:
type StringToNumber<T> = {
[K in keyof T]: T[K] extends string ? number : T[K]
}
function stringToLength<T extends Record<string, unknown>>(obj: T): StringToNumber<T> {
const result: Record<string, unknown> = {};
for (const key in obj) {
result[key] = typeof obj[key] === 'string' ? obj[key].length : obj[key];
}
return result as StringToNumber<T>;
}
const data = {
name: "Alice",
age: 30,
city: "New York"
};
const lengths = stringToLength(data);
lengths.name // number
lengths.age // number
lengths.city // number
[0] https://www.typescriptlang.org/play/?#code/GYVwdgxgLglg9mABAJwKYFs4DdUDEaoA2AJgDwAqANIgNKKoAeUqYxAzogNaoCecwicgD4AFHABGAKwBcg6sAIlZNAJSyA8uhhQK1GkMQBvALAAoRBcQQEbKEcQBtBUWIBdWQH1qAOl9pbiAC+iAC8iBKSANxmliioUCDISP5Q0aaBZmZQPAAOqIgACqjIbAih9mAAhuiosrbIMGAA5pGIlU21iGAg6OLFQWlmxKgQhJVoVjZ2ObJFJQiDptZgAf4ghHZhaJg4+C4iOdQA5O2oRyqtAPSXiJrapHOlYNQARKcvQmbXsYgAegD8QA https://www.typescriptlang.org/play/?#code/GYVwdgxgLglg9mABA...
[1] https://www.typescriptlang.org/play/?#code/C4TwDgpgBAysBOBLAdgcwCoHsByBXAtgEYTwA86AfFALxQDeAsAFBStQDaA0lClANYQQmAGZR0AXQBcYruKgQAHsAjIAJgGco6hClRQA-FGQFi8KNPSzmAX2bNhuZAGNgiTMi060WADIrUwAAW5PJKKhpQAEoQTpjwqqTaSGgANFCOfMiYAO7IFBQAFJiEAFYWAJTScMkYOCYk5FSMLGyxyNpQ8BDquAA2wNLRsfGJXqhpGVm5VLR01gDczGxQwnFQBW0dAiA8HsUl5fRLy2xdPf3s23K0oJAiUPuXgtfUtADkSbpvBg+lTyDiAB0vX8QXMvxK-3EixarFssM6EGAuHgHjOfWAUAAhppqrosHgiA1KDD4cxNpjVFjgFiaEcEcgsfgINIAEQAQV6iCcEFZKWOrCxqBZUAAzAAGfkIpyIUBs7AQbJQACacT4rJsMPJ7g6ILQQU0tE+3kwfn1gQKVJp5S1TD1AUC6kBjOZUAA9G6jPV4Mx7QbAULoB6vUSfXbQY7ATLQO7PcZQ0A https://www.typescriptlang.org/play/?#code/C4TwDgpgBAysBOBLA...
edit: provided links to TS playground
- jy14898 2y agoThe tools typescript provides are a little pointless if it allows you to do stuff like this (imo): const r1: { a: number; b: number } = { a: 10, b: 20 }; const r2: { a: number } = r1; const r3: { a: number; b: string } = { b: "hello", ...r2 }; console.log(r3.b) // typescript thinks it's a string, but actually it's a number
- blue_pants 2y agoYeah, it's definitely not ideal, but even with its many flaws I prefer TS over plain JS. The problem in question can be "fixed" like this const r1: { a: number; b: number } = { a: 10, b: 20 }; const r2 = r1 satisfies { a: number }; const r3: { a: number; b: string } = { b: "hello", ...r2 }; Now, TS would warn us that "'b' is specified more than once, so this usage will be overwritten". And if we remove b property -- "Type 'number' is not assignable to type 'string'" Another "fix" would be to avoid using spread operator and specify every property manually . Both of these solutions are far from ideal, I agree. --- I don't advocate TS in this thread though; I genuinely want to understand what makes row polymorphism different, and after reading several articles and harassing Claude Sonnet about it, I still didn't grasp what row polymorphism allows over what TS has.
- wk_end 2y agoAs far as I understand it, row polymorphism wouldn’t allow the given example. Or to put it another way, the spread operator is impossible to type soundly in the presence of structural subtyping because the type system doesn’t capture the “openness” of the record’s type, the potential presence of additional fields. Whereas with row polymorphism, to some degree or another, you can.