Skip to content

Commit

Permalink
test
Browse files Browse the repository at this point in the history
  • Loading branch information
riccardoperra committed Jan 5, 2025
1 parent e2c797f commit 6eee6bf
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 17 deletions.
2 changes: 1 addition & 1 deletion packages/angular-table/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
],
"scripts": {
"clean": "rimraf ./build",
"test:types": "tsc --noEmit",
"test:types": "tsc --noEmit && vitest --typecheck",
"test:lib": "vitest",
"test:lib:dev": "vitest --watch",
"build": "ng-packagr -p ng-package.json -c tsconfig.build.json && rimraf ./build/lib/package.json"
Expand Down
42 changes: 26 additions & 16 deletions packages/angular-table/src/flex-render/flex-render-component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
ComponentMirror,
Injector,
input,
InputSignal,
reflectComponentType,
Type,
Expand All @@ -9,27 +10,36 @@ import {
type Inputs<T> = {
[K in keyof T as T[K] extends InputSignal<infer R>
? K
: never]: T[K] extends InputSignal<infer R> ? R : never
: never]?: T[K] extends InputSignal<infer R> ? R : never
}

type HasUndefinedProperty<T> = keyof T extends never
? true
: keyof {
[K in keyof T as undefined extends T[K] ? K : never]: T[K]
} extends never
? false
: true
type OptionalKeys<T, K = keyof T> = K extends keyof T
? T[K] extends Required<T>[K]
? undefined extends T[K]
? K
: never
: K
: never

interface FlexRenderRequiredOptions<
TComponent,
TInputs extends Record<string, any>,
> {
interface FlexRenderRequiredOptions<TInputs extends Record<string, any>> {
/**
* Component instance inputs. They will be set via [componentRef.setInput API](https://angular.dev/api/core/ComponentRef#setInput)
*/
inputs: TInputs
/**
* Optional {@link Injector} that will be used when rendering the component
*/
injector?: Injector
}

interface FlexRenderOptions<TComponent, TInputs extends Record<string, any>> {
interface FlexRenderOptions<TInputs extends Record<string, any>> {
/**
* Component instance inputs. They will be set via [componentRef.setInput API](https://angular.dev/api/core/ComponentRef#setInput)
*/
inputs?: TInputs
/**
* Optional {@link Injector} that will be used when rendering the component
*/
injector?: Injector
}

Expand All @@ -44,9 +54,9 @@ export function flexRenderComponent<
TInputs extends Inputs<TComponent> = Inputs<TComponent>,
>(
component: Type<TComponent>,
...options: HasUndefinedProperty<TInputs> extends true
? [FlexRenderOptions<TComponent, TInputs>?]
: [FlexRenderRequiredOptions<TComponent, TInputs>]
...options: OptionalKeys<TInputs> extends never
? [FlexRenderOptions<TInputs>?]
: [FlexRenderRequiredOptions<TInputs>]
) {
const { inputs, injector } = options?.[0] ?? {}
return new FlexRenderComponent(component, inputs, injector)
Expand Down
27 changes: 27 additions & 0 deletions packages/angular-table/tests/flex-render-component.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { input } from '@angular/core'
import { test } from 'vitest'
import { flexRenderComponent } from '../src'

test('Infer component inputs', () => {
class Test {
readonly input1 = input<string>()
}

// @ts-expect-error Must pass right type as a value
flexRenderComponent(Test, { inputs: { input1: 1 } })

// Input is optional so we can skip passing the property
flexRenderComponent(Test, { inputs: {} })
})

test('Options are mandatory when given component has required inputs', () => {
class Test {
readonly input1 = input<string>()
readonly requiredInput1 = input.required<string>()
}

// @ts-expect-error Required input
flexRenderComponent(Test)

flexRenderComponent(Test, { inputs: { requiredInput1: 'My value' } })
})

0 comments on commit 6eee6bf

Please sign in to comment.