Skip to content

Commit e306333

Browse files
committed
fix(sortablejs): Make union types work
By default, conditional types are distributive when given a union type [1]. However, we don’t actually use anywhere the fact that arrays are homogeneous, and on the other hand distributive typing forbids heterogeneous arrays, like an array that contains values and sub-arrays. Adding square brackets allows heterogeneous arrays without disallowing homogeneous ones (since `A[]|B[]` is a subtype of `(A|B)[]`). Add an example demonstrating this – this example doesn’t compile without my modification, but it does compile with the modification (so it also functions as a regression test). [1] https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types
1 parent d78fb6d commit e306333

File tree

5 files changed

+44
-1
lines changed

5 files changed

+44
-1
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<h3 class="h4">Button group</h3>
2+
3+
<div class="btn-group"
4+
[nxtSortablejs]="elems">
5+
<button type="button"
6+
class="btn btn-secondary"
7+
*ngFor="let elem of elems">
8+
<ng-container *ngIf="!isArray(elem)">{{ elem }}</ng-container>
9+
<ul *ngIf="isArray(elem)"
10+
class="list-unstyled m-0">
11+
<li *ngFor="let num of elem">{{num}}</li>
12+
</ul>
13+
</button>
14+
</div>
15+
16+
<h3 class="h4">The actual model</h3>
17+
18+
<app-code-block [code]="elems | json"
19+
[languages]="['json']"
20+
[copy]="false"></app-code-block>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { Component, ViewEncapsulation } from '@angular/core'
2+
3+
@Component({
4+
selector: 'app-union-example',
5+
templateUrl: './union-example.component.html',
6+
encapsulation: ViewEncapsulation.Emulated
7+
})
8+
export class UnionExampleComponent {
9+
readonly elems = [
10+
1,
11+
2,
12+
[3, 4],
13+
]
14+
readonly isArray = Array.isArray
15+
}

packages/demo/src/app/sortablejs/sortablejs.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { MetaModule } from '../meta/meta.module'
1111
import { OutputsTableComponent } from '../outputs-table/outputs-table.component'
1212
import { BasicExampleComponent } from './examples/basic-example/basic-example.component'
1313
import { ComplexExampleComponent } from './examples/complex-example/complex-example.component'
14+
import { UnionExampleComponent } from './examples/union-example/union-example.component'
1415
import { DisabledOptionsComponent } from './examples/disabled-options/disabled-options.component'
1516
import { EventsComponent } from './examples/events/events.component'
1617
import { FormArrayComponent } from './examples/form-array/form-array.component'
@@ -32,6 +33,7 @@ import { AppSortablejsComponent } from './sortablejs/sortablejs.component'
3233
TransferListsComponent,
3334
ItemCloneComponent,
3435
ComplexExampleComponent,
36+
UnionExampleComponent,
3537
GettingStartedComponent
3638
],
3739
imports: [

packages/demo/src/app/sortablejs/sortablejs/sortablejs.component.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ export class AppSortablejsComponent extends WaitLoad implements OnInit {
5757
name: 'Complex example',
5858
description: 'Each list can have different options and restrictions.',
5959
include: ['html', 'ts']
60+
},
61+
{
62+
path: 'union-example',
63+
name: 'Union example',
64+
description: 'The list items can be of different types (the element type can be a union type).',
65+
include: ['html', 'ts']
6066
}
6167
)
6268
.map(p => Promise.all([

packages/sortablejs/src/lib/sortablejs.directive.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { GLOBALS } from './globals'
2020
import { SortablejsBindings } from './sortablejs-bindings'
2121
import { SortablejsService } from './sortablejs.service'
2222

23-
export type SortableData<T> = T extends AbstractControl ? (FormArray<T> | T[]) : T[]
23+
export type SortableData<T> = [T] extends [AbstractControl] ? (FormArray<T> | T[]) : T[]
2424
export type CloneFunction<T> = (item: T) => T
2525

2626
/** @internal */

0 commit comments

Comments
 (0)