<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Marcel Laverdet on Medium]]></title>
        <description><![CDATA[Stories by Marcel Laverdet on Medium]]></description>
        <link>https://medium.com/@laverdet?source=rss-3a5c622826da------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*ItU8FMF1TqV0rGU_.</url>
            <title>Stories by Marcel Laverdet on Medium</title>
            <link>https://medium.com/@laverdet?source=rss-3a5c622826da------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 05:05:31 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@laverdet/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[TypeScript safe upcast — `satisfies … as …`]]></title>
            <link>https://medium.com/@laverdet/typescript-safe-upcast-satisfies-as-da1fdee4d6ea?source=rss-3a5c622826da------2</link>
            <guid isPermaLink="false">https://medium.com/p/da1fdee4d6ea</guid>
            <category><![CDATA[typescript]]></category>
            <dc:creator><![CDATA[Marcel Laverdet]]></dc:creator>
            <pubDate>Thu, 26 Oct 2023 21:18:27 GMT</pubDate>
            <atom:updated>2023-10-26T21:18:27.207Z</atom:updated>
            <content:encoded><![CDATA[<h3>TypeScript safe upcast — `satisfies … as …`</h3><p>In TypeScript sometimes we need the as type operator to massage something which we know is allowed by the runtime, but the type system is not engineered to handle. This operator is inherently dangerous and will upcast any type to any other type as long as it has some properties in common. I’m proposing adoption of the satisfies U as T pattern to alleviate some of this danger.</p><p>An example of a situation in which you might need as is a method like Set.prototype.has, which should accept covariant parameters, but is not expressed in the type system:</p><pre>declare const set: Set&lt;string&gt;;<br>declare const id: number | string;<br>// Argument of type &#39;string | number&#39; is not assignable to parameter of type &#39;string&#39;.<br>// Type &#39;number&#39; is not assignable to type &#39;string&#39;.ts(2345)<br>const has = set.has(id);<br></pre><p>Ehh, ok? Of course, string | number is not assignable to string but this lookup is totally reasonable. There’s a few options to resolve the error and many of them are not really good. One option is to cast id using the as operator: set.has(id as string) but that has safety issues:</p><pre>declare const set: Set&lt;string&gt;;<br>declare const id: { length: number };<br>// TypeScript thinks this is fine<br>const has = set.has(id as string);</pre><p>You might also run into issues where a package author has defined the incorrect types for their package. This is especially common if you make use of the readonly modifier, or use very generic types like PromiseLike&lt;T&gt; instead of Promise&lt;T&gt;:</p><pre>// This is pure function defined by an npm package that will be annoying<br>// to modify<br>declare const accumulate: (list: number[]) =&gt; number;<br>// This is our array which is defined as readonly to prevent modification<br>declare const values: readonly number[];<br>// Argument of type &#39;readonly number[]&#39; is not assignable to parameter of type &#39;number[]&#39;.<br>// The type &#39;readonly number[]&#39; is &#39;readonly&#39; and cannot be assigned to the mutable type &#39;number[]&#39;.ts(2345)<br>accumulate(values);</pre><p>Again, you can work around it with the as operator but the danger is still apparent:</p><pre>declare const sum: (list: number[]) =&gt; number;<br>declare const values: readonly number[];<br>// Sure, ok<br>sum(values as number[]);<br>declare const objects: { toString: () =&gt; string }[];<br>// Wait, this is wrong<br>sum(objects as number[]);</pre><p>TypeScript 4.9 introduced the satisfies operator which asserts that a given type “satisfies” this given constraint without changing the type. If we combine the two operators the result is a “safe upcast” operation. This was <a href="https://github.com/microsoft/TypeScript/issues/47920#issuecomment-1054480996">proposed by Ryan Cavanaugh</a> in the original GitHub discussion on the operator.</p><pre>declare const sum: (list: number[]) =&gt; number;<br>declare const values: readonly number[];<br>// Ok.<br>sum(values satisfies readonly number[] as number[]);<br>declare const objects: { toString: () =&gt; string }[];<br>// Raises an error!<br>sum(objects satisfies readonly number[] as number[]);</pre><p>The syntax is verbose but serves the purpose of “burning in” the expected “in” type <em>and</em> the expected “out” type. The result is software which is more sound and resilient to refactors.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=da1fdee4d6ea" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>