Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@rictic
Copy link
Collaborator

@rictic rictic commented Aug 13, 2025

If a directive's type is written such that it returns sufficiently specific DirectiveResults, the TypeScript type system can tell the effective type that a DirectiveResult will render to its part.

By itself, this doesn't do much, but I've also got a patch to rune's lit analyzer to better type check directives there.

@rictic rictic requested a review from kevinpschaaf as a code owner August 13, 2025 00:04
@changeset-bot
Copy link

changeset-bot bot commented Aug 13, 2025

🦋 Changeset detected

Latest commit: 3af7b31

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
lit-html Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Contributor

github-actions bot commented Aug 13, 2025

📊 Tachometer Benchmark Results

Summary

nop-update

  • this-change, tip-of-tree, previous-release: unsure 🔍 -3% - +7% (-0.35ms - +0.77ms)
    this-change vs tip-of-tree

render

  • this-change: 41.67ms - 51.51ms
  • this-change, tip-of-tree, previous-release: unsure 🔍 -5% - +4% (-1.01ms - +0.78ms)
    this-change vs tip-of-tree
  • this-change, tip-of-tree, previous-release: unsure 🔍 -2% - +2% (-0.71ms - +0.69ms)
    this-change vs tip-of-tree
  • this-change, tip-of-tree, previous-release: unsure 🔍 -21% - +30% (-11.87ms - +16.73ms)
    this-change vs tip-of-tree

update

  • this-change: 459.64ms - 464.62ms
  • this-change, tip-of-tree, previous-release: unsure 🔍 -3% - +7% (-1.28ms - +2.40ms)
    this-change vs tip-of-tree
  • this-change, tip-of-tree, previous-release: unsure 🔍 -2% - +1% (-1.68ms - +0.95ms)
    this-change vs tip-of-tree
  • this-change, tip-of-tree, previous-release: unsure 🔍 -1% - +1% (-5.22ms - +4.83ms)
    this-change vs tip-of-tree

update-reflect

  • this-change: 447.01ms - 450.09ms
  • this-change, tip-of-tree, previous-release: unsure 🔍 -1% - +1% (-3.49ms - +2.98ms)
    this-change vs tip-of-tree

Results

this-change

render

VersionAvg timevs
41.67ms - 51.51ms-

update

VersionAvg timevs
459.64ms - 464.62ms-

update-reflect

VersionAvg timevs
447.01ms - 450.09ms-
this-change, tip-of-tree, previous-release

render

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
19.21ms - 20.40ms-unsure 🔍
-5% - +4%
-1.01ms - +0.78ms
unsure 🔍
-4% - +5%
-0.82ms - +1.04ms
tip-of-tree
tip-of-tree
19.25ms - 20.60msunsure 🔍
-4% - +5%
-0.78ms - +1.01ms
-unsure 🔍
-4% - +6%
-0.76ms - +1.21ms
previous-release
previous-release
18.97ms - 20.42msunsure 🔍
-5% - +4%
-1.04ms - +0.82ms
unsure 🔍
-6% - +4%
-1.21ms - +0.76ms
-

update

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
36.35ms - 39.01ms-unsure 🔍
-3% - +7%
-1.28ms - +2.40ms
slower ❌
0% - 11%
0.19ms - 3.89ms
tip-of-tree
tip-of-tree
35.85ms - 38.39msunsure 🔍
-6% - +3%
-2.40ms - +1.28ms
-unsure 🔍
-1% - +9%
-0.33ms - +3.29ms
previous-release
previous-release
34.34ms - 36.93msfaster ✔
1% - 10%
0.19ms - 3.89ms
unsure 🔍
-9% - +1%
-3.29ms - +0.33ms
-

nop-update

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
11.18ms - 12.04ms-unsure 🔍
-3% - +7%
-0.35ms - +0.77ms
unsure 🔍
-5% - +6%
-0.60ms - +0.65ms
tip-of-tree
tip-of-tree
11.03ms - 11.77msunsure 🔍
-7% - +3%
-0.77ms - +0.35ms
-unsure 🔍
-7% - +3%
-0.77ms - +0.40ms
previous-release
previous-release
11.13ms - 12.04msunsure 🔍
-6% - +5%
-0.65ms - +0.60ms
unsure 🔍
-4% - +7%
-0.40ms - +0.77ms
-
this-change, tip-of-tree, previous-release

render

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
34.95ms - 35.79ms-unsure 🔍
-2% - +2%
-0.71ms - +0.69ms
unsure 🔍
-2% - +1%
-0.79ms - +0.43ms
tip-of-tree
tip-of-tree
34.82ms - 35.94msunsure 🔍
-2% - +2%
-0.69ms - +0.71ms
-unsure 🔍
-2% - +2%
-0.88ms - +0.54ms
previous-release
previous-release
35.11ms - 35.99msunsure 🔍
-1% - +2%
-0.43ms - +0.79ms
unsure 🔍
-2% - +3%
-0.54ms - +0.88ms
-

update

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
71.15ms - 72.96ms-unsure 🔍
-2% - +1%
-1.68ms - +0.95ms
unsure 🔍
-1% - +2%
-0.63ms - +1.75ms
tip-of-tree
tip-of-tree
71.47ms - 73.37msunsure 🔍
-1% - +2%
-0.95ms - +1.68ms
-unsure 🔍
-0% - +3%
-0.30ms - +2.15ms
previous-release
previous-release
70.73ms - 72.26msunsure 🔍
-2% - +1%
-1.75ms - +0.63ms
unsure 🔍
-3% - +0%
-2.15ms - +0.30ms
-
this-change, tip-of-tree, previous-release

render

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
49.52ms - 69.85ms-unsure 🔍
-21% - +30%
-11.87ms - +16.73ms
unsure 🔍
-7% - +55%
-2.08ms - +24.96ms
tip-of-tree
tip-of-tree
47.20ms - 67.32msunsure 🔍
-28% - +19%
-16.73ms - +11.87ms
-unsure 🔍
-12% - +49%
-4.44ms - +22.45ms
previous-release
previous-release
39.33ms - 57.17msunsure 🔍
-39% - +1%
-24.96ms - +2.08ms
unsure 🔍
-37% - +6%
-22.45ms - +4.44ms
-

update

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
461.19ms - 468.67ms-unsure 🔍
-1% - +1%
-5.22ms - +4.83ms
unsure 🔍
-1% - +1%
-6.78ms - +3.01ms
tip-of-tree
tip-of-tree
461.78ms - 468.48msunsure 🔍
-1% - +1%
-4.83ms - +5.22ms
-unsure 🔍
-1% - +1%
-6.30ms - +2.91ms
previous-release
previous-release
463.66ms - 469.98msunsure 🔍
-1% - +1%
-3.01ms - +6.78ms
unsure 🔍
-1% - +1%
-2.91ms - +6.30ms
-

update-reflect

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
469.99ms - 474.52ms-unsure 🔍
-1% - +1%
-3.49ms - +2.98ms
unsure 🔍
-1% - +0%
-6.03ms - +0.64ms
tip-of-tree
tip-of-tree
470.21ms - 474.82msunsure 🔍
-1% - +1%
-2.98ms - +3.49ms
-unsure 🔍
-1% - +0%
-5.80ms - +0.92ms
previous-release
previous-release
472.50ms - 477.40msunsure 🔍
-0% - +1%
-0.64ms - +6.03ms
unsure 🔍
-0% - +1%
-0.92ms - +5.80ms
-

tachometer-reporter-action v2 for Benchmarks

@rictic rictic force-pushed the generic-directives branch from 4f09a67 to e01f2d3 Compare August 13, 2025 00:05
@github-actions
Copy link
Contributor

The size of lit-html.js and lit-core.min.js are as expected.

Copy link
Collaborator

@justinfagnani justinfagnani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with one question.

I think you need to run format too.


export interface DirectiveClass {
new (part: PartInfo): Directive;
export interface DirectiveClass<RenderAs = unknown> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need this type parameter? You'd normally get the return type with ReturnType<C['render']>.

Is it so that you can feed in a type variable from an override type for directive(), like in Guard? If so, can you leave a comment?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can actually use infer (and similar tricks in the TypeScript type system) to get around needing this at all. I've updated the PR to not need any changes to the common directive types, with a little care, a directive can just be written to put enough information on the DirectiveResults it makes.

@rictic rictic changed the title Make the Directive types generic, for better type checking of lit templates Make our directives generic, for better type checking of lit templates Aug 15, 2025
@rictic rictic enabled auto-merge (squash) August 15, 2025 04:02
}

interface Until {
<T>(val: T): DirectiveResult<typeof UntilDirective<T>>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't this be:

Suggested change
<T>(val: T): DirectiveResult<typeof UntilDirective<T>>;
<T>(...args: Array<T>): DirectiveResult<typeof UntilDirective<T>>;

Won't TS infer T as a union of the arg types, just like you're doing manually?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Paired on fix.

rictic and others added 8 commits August 21, 2025 12:21
…plates.

This allows a custom directive to carry enough information that the TypeScript type system can tell the type that a DirectiveResult will render.

This is backwards compatible, existing directives will generally be inferred to render the type of their `render` functions. Many directives can be updated to themselves be generic, to better express their types, and I've done this for our built in directives.

By itself, this doesn't do much, but I've also got a patch to rune's lit analyzer to better type check directives there.
Turns out, all we need is to make our own generic directives generic enough so that we can infer the return type of their render functions from their DirectiveResult. No need to change directive.ts or async-directive.ts at all.
@rictic rictic force-pushed the generic-directives branch from 2180310 to 8cee2db Compare August 21, 2025 19:21
@rictic rictic merged commit c36626b into main Aug 22, 2025
10 checks passed
@rictic rictic deleted the generic-directives branch August 22, 2025 01:31
@lit-robot lit-robot mentioned this pull request Dec 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants