Popular New Releases in Autocomplete
autocomplete
spec-build-number-0.694.0
downshift
v6.1.7
vue-multiselect
3.0.0-alpha.1
autoComplete.js
v10.2.6
ng-select
v8.1.1
Popular Libraries in Autocomplete
by zsh-users shell
18420 MIT
Fish-like autosuggestions for zsh
by withfig typescript
16522 MIT
Fig adds autocomplete to your terminal.
by twitter javascript
16314 MIT
typeahead.js is a fast and fully-featured autocomplete library
by downshift-js javascript
10398 MIT
🏎 A set of primitives to build simple, flexible, WAI-ARIA compliant React autocomplete, combobox or select dropdown components.
by shentao javascript
6049 MIT
Universal select/multiselect/tagging component for Vue.js
by ankane ruby
5846 MIT
Intelligent search made easy
by algolia javascript
5366 MIT
:globe_with_meridians: Turn any <input> into an address autocomplete
by SublimeCodeIntel python
5046 NOASSERTION
💡 Full-featured code intelligence and smart autocomplete for Sublime Text
by TarekRaafat javascript
3505 Apache-2.0
Simple autocomplete pure vanilla Javascript library.
Trending New libraries in Autocomplete
by withfig typescript
16522 MIT
Fig adds autocomplete to your terminal.
by marlonrichert shell
1503 MIT
🤖 Real-time type-ahead completion for Zsh. Asynchronous find-as-you-type autocompletion.
by asantibanez php
319 MIT
Livewire component for dependant and/or searchable select inputs
by kiteco typescript
311 NOASSERTION
Kite Autocomplete Extension for JupyterLab
by segmentio typescript
295 MIT
A typescript language service plugin that gives superpowers to SQL tagged template literals.
by simoebenhida typescript
151 MIT
Laravel VScode extension
by ejmudi typescript
142 MIT
A React component for Autocomplete Hint.
by mattzollinhofer javascript
84 MIT
An autocomplete/typeahead component for Vue 2 and Bootstrap 4
by Gapur javascript
58
🏆 Best practice with Google Place Autocomplete API on React
Top Authors in Autocomplete
1
5 Libraries
8665
2
4 Libraries
44
3
3 Libraries
330
4
3 Libraries
1138
5
3 Libraries
376
6
3 Libraries
989
7
3 Libraries
20
8
3 Libraries
12
9
3 Libraries
182
10
2 Libraries
24
1
5 Libraries
8665
2
4 Libraries
44
3
3 Libraries
330
4
3 Libraries
1138
5
3 Libraries
376
6
3 Libraries
989
7
3 Libraries
20
8
3 Libraries
12
9
3 Libraries
182
10
2 Libraries
24
Trending Kits in Autocomplete
No Trending Kits are available at this moment for Autocomplete
Trending Discussions on Autocomplete
Plotly dash table add rows and update input data
How to fix: "@angular/fire"' has no exported member 'AngularFireModule'.ts(2305) ionic, firebase, angular
Module not found: Error: Can't resolve 'date-fns/addDays' in 'C:\Users\
Simulate Bash's COMPREPLY response without actually completing it
React/Socket.io not displaying latest message passed down as prop
Unable to build and deploy Rails 6.0.4.1 app on heroku - Throws gyp verb cli error
Getting keyboard navigation to work with MUI Autocomplete and SimpleBar for react
Disable irb autocomplete
Why typescript does not properly infer T[K] with <T extends Person, K extends keyof T> generic?
Typescript: deep keyof of a nested object, with related type
QUESTION
Plotly dash table add rows and update input data
Asked 2022-Feb-15 at 05:25I'm trying to make a dash table based on input data but I'm stucking in add more rows to add new inputs. Actually I read this docs and I know that I can directly input in dash table but I want to update dash table from input.
Below is my code:
1import pandas as pd
2import numpy as np
3from datetime import datetime as dt
4import plotly.express as px
5import dash
6import dash_html_components as html
7import dash_core_components as dcc
8from dash.dependencies import Input, Output, State
9import dash_table
10import dash_bootstrap_components as dbc
11from dash_extensions import Download
12from dash_extensions.snippets import send_data_frame
13import glob
14import os
15from pandas.tseries.offsets import BDay
16import plotly.graph_objects as go
17
18app = dash.Dash(__name__)
19
20MD23 = pd.DataFrame({'Number':[],
21 'PW':[],
22 'Name 1':[],
23 'Name 2':[],
24 'Email':[],
25 'Web':[],
26 'Abc':[]})
27# ------------------------------------------------------------------------
28
29input_types = ['number', 'password', 'text', 'tel', 'email', 'url', 'search']
30
31app.layout = html.Div([
32 html.Div([
33 dcc.Input(
34 id='my_{}'.format(x),
35 type=x,
36 placeholder="insert {}".format(x), # A hint to the user of what can be entered in the control
37 minLength=0, maxLength=50, # Ranges for character length inside input box
38 autoComplete='on',
39 disabled=False, # Disable input box
40 readOnly=False, # Make input box read only
41 required=False, # Require user to insert something into input box
42 size="20", # Number of characters that will be visible inside box
43 ) for x in input_types
44 ]),
45
46 html.Br(),
47
48 html.Button('Add Row',id='add_row',n_clicks=0),
49
50 dbc.Row([
51 dbc.Col([html.H5('List',className='text-center'),
52 dash_table.DataTable(
53 id='table-container_3',
54 data=[],
55 columns=[{"name":i_3,"id":i_3,'type':'numeric'} for i_3 in MD23.columns],
56 style_table={'overflow':'scroll','height':600},
57 style_cell={'textAlign':'center'},
58 row_deletable=True,
59 editable=True)
60 ],width={'size':12,"offset":0,'order':1})
61 ]),
62])
63
64
65@app.callback(Output('table-container_3', 'data'),
66 [Input('my_{}'.format(x),'value')for x in input_types])
67
68def update_data(selected_number, selected_pw,
69 selected_text, selected_tel,
70 selected_email,selected_url,
71 selected_search):
72
73 data = pd.DataFrame({'Number':[selected_number],
74 'PW':[selected_pw],
75 'Name 1':[selected_text],
76 'Name 2':[selected_tel],
77 'Email':[selected_email],
78 'Web':[selected_url],
79 'Abc':[selected_search]})
80
81 return data.to_dict(orient='records')
82
83
84# ------------------------------------------------------------------------
85if __name__ == '__main__':
86 app.run_server(debug=False)
87
I tried to add rows as below but it's not worked:
1import pandas as pd
2import numpy as np
3from datetime import datetime as dt
4import plotly.express as px
5import dash
6import dash_html_components as html
7import dash_core_components as dcc
8from dash.dependencies import Input, Output, State
9import dash_table
10import dash_bootstrap_components as dbc
11from dash_extensions import Download
12from dash_extensions.snippets import send_data_frame
13import glob
14import os
15from pandas.tseries.offsets import BDay
16import plotly.graph_objects as go
17
18app = dash.Dash(__name__)
19
20MD23 = pd.DataFrame({'Number':[],
21 'PW':[],
22 'Name 1':[],
23 'Name 2':[],
24 'Email':[],
25 'Web':[],
26 'Abc':[]})
27# ------------------------------------------------------------------------
28
29input_types = ['number', 'password', 'text', 'tel', 'email', 'url', 'search']
30
31app.layout = html.Div([
32 html.Div([
33 dcc.Input(
34 id='my_{}'.format(x),
35 type=x,
36 placeholder="insert {}".format(x), # A hint to the user of what can be entered in the control
37 minLength=0, maxLength=50, # Ranges for character length inside input box
38 autoComplete='on',
39 disabled=False, # Disable input box
40 readOnly=False, # Make input box read only
41 required=False, # Require user to insert something into input box
42 size="20", # Number of characters that will be visible inside box
43 ) for x in input_types
44 ]),
45
46 html.Br(),
47
48 html.Button('Add Row',id='add_row',n_clicks=0),
49
50 dbc.Row([
51 dbc.Col([html.H5('List',className='text-center'),
52 dash_table.DataTable(
53 id='table-container_3',
54 data=[],
55 columns=[{"name":i_3,"id":i_3,'type':'numeric'} for i_3 in MD23.columns],
56 style_table={'overflow':'scroll','height':600},
57 style_cell={'textAlign':'center'},
58 row_deletable=True,
59 editable=True)
60 ],width={'size':12,"offset":0,'order':1})
61 ]),
62])
63
64
65@app.callback(Output('table-container_3', 'data'),
66 [Input('my_{}'.format(x),'value')for x in input_types])
67
68def update_data(selected_number, selected_pw,
69 selected_text, selected_tel,
70 selected_email,selected_url,
71 selected_search):
72
73 data = pd.DataFrame({'Number':[selected_number],
74 'PW':[selected_pw],
75 'Name 1':[selected_text],
76 'Name 2':[selected_tel],
77 'Email':[selected_email],
78 'Web':[selected_url],
79 'Abc':[selected_search]})
80
81 return data.to_dict(orient='records')
82
83
84# ------------------------------------------------------------------------
85if __name__ == '__main__':
86 app.run_server(debug=False)
87@app.callback(
88 Output('table-container_3', 'data'),
89 Input('add_row', 'n_clicks'),
90 State('table-container_3', 'data'),
91 State('table-container_3', 'columns'))
92
93def add_row(n_clicks, rows, columns):
94 if n_clicks > 0:
95 rows.append()
96 return rows
97
I really need suggestions to solve this problem. Thank you so much.
ANSWER
Answered 2022-Feb-15 at 05:25tran Try to replace your callback with this callback:
1import pandas as pd
2import numpy as np
3from datetime import datetime as dt
4import plotly.express as px
5import dash
6import dash_html_components as html
7import dash_core_components as dcc
8from dash.dependencies import Input, Output, State
9import dash_table
10import dash_bootstrap_components as dbc
11from dash_extensions import Download
12from dash_extensions.snippets import send_data_frame
13import glob
14import os
15from pandas.tseries.offsets import BDay
16import plotly.graph_objects as go
17
18app = dash.Dash(__name__)
19
20MD23 = pd.DataFrame({'Number':[],
21 'PW':[],
22 'Name 1':[],
23 'Name 2':[],
24 'Email':[],
25 'Web':[],
26 'Abc':[]})
27# ------------------------------------------------------------------------
28
29input_types = ['number', 'password', 'text', 'tel', 'email', 'url', 'search']
30
31app.layout = html.Div([
32 html.Div([
33 dcc.Input(
34 id='my_{}'.format(x),
35 type=x,
36 placeholder="insert {}".format(x), # A hint to the user of what can be entered in the control
37 minLength=0, maxLength=50, # Ranges for character length inside input box
38 autoComplete='on',
39 disabled=False, # Disable input box
40 readOnly=False, # Make input box read only
41 required=False, # Require user to insert something into input box
42 size="20", # Number of characters that will be visible inside box
43 ) for x in input_types
44 ]),
45
46 html.Br(),
47
48 html.Button('Add Row',id='add_row',n_clicks=0),
49
50 dbc.Row([
51 dbc.Col([html.H5('List',className='text-center'),
52 dash_table.DataTable(
53 id='table-container_3',
54 data=[],
55 columns=[{"name":i_3,"id":i_3,'type':'numeric'} for i_3 in MD23.columns],
56 style_table={'overflow':'scroll','height':600},
57 style_cell={'textAlign':'center'},
58 row_deletable=True,
59 editable=True)
60 ],width={'size':12,"offset":0,'order':1})
61 ]),
62])
63
64
65@app.callback(Output('table-container_3', 'data'),
66 [Input('my_{}'.format(x),'value')for x in input_types])
67
68def update_data(selected_number, selected_pw,
69 selected_text, selected_tel,
70 selected_email,selected_url,
71 selected_search):
72
73 data = pd.DataFrame({'Number':[selected_number],
74 'PW':[selected_pw],
75 'Name 1':[selected_text],
76 'Name 2':[selected_tel],
77 'Email':[selected_email],
78 'Web':[selected_url],
79 'Abc':[selected_search]})
80
81 return data.to_dict(orient='records')
82
83
84# ------------------------------------------------------------------------
85if __name__ == '__main__':
86 app.run_server(debug=False)
87@app.callback(
88 Output('table-container_3', 'data'),
89 Input('add_row', 'n_clicks'),
90 State('table-container_3', 'data'),
91 State('table-container_3', 'columns'))
92
93def add_row(n_clicks, rows, columns):
94 if n_clicks > 0:
95 rows.append()
96 return rows
97@app.callback(
98Output('table-container_3', 'data'),
99Input('add_row', 'n_clicks'),
100[State('table-container_3', 'data'),
101State('table-container_3', 'columns')]+
102[State('my_{}'.format(x), 'value') for x in input_types])
103def add_row(n_clicks, rows, columns, selected_number, selected_pw,
104 selected_text, selected_tel,
105 selected_email, selected_url,
106 selected_search):
107
108if n_clicks > 0:
109 rows.append({c['id']: r for c,r in zip(columns, [selected_number, selected_pw, selected_text, selected_tel, selected_email, selected_url, selected_search])})
110
111return rows
112
QUESTION
How to fix: "@angular/fire"' has no exported member 'AngularFireModule'.ts(2305) ionic, firebase, angular
Asked 2022-Feb-11 at 07:31I'm trying to connect my app with a firebase db, but I receive 4 error messages on app.module.ts:
1'"@angular/fire"' has no exported member 'AngularFireModule'.ts(2305),
2'"@angular/fire/storage"' has no exported member 'AngularFireStorageModule'.ts(2305)
3'"@angular/fire/database"' has no exported member 'AngularFireDatabaseModule'.ts(2305)
4'"@angular/fire/auth"' has no exported member 'AngularFireAuthModule'.ts(2305)
5
here is my package.json file:
1'"@angular/fire"' has no exported member 'AngularFireModule'.ts(2305),
2'"@angular/fire/storage"' has no exported member 'AngularFireStorageModule'.ts(2305)
3'"@angular/fire/database"' has no exported member 'AngularFireDatabaseModule'.ts(2305)
4'"@angular/fire/auth"' has no exported member 'AngularFireAuthModule'.ts(2305)
5{
6 "name": "gescable",
7 "version": "0.0.1",
8 "author": "Ionic Framework",
9 "homepage": "https://ionicframework.com/",
10 "scripts": {
11 "ng": "ng",
12 "start": "ng serve",
13 "build": "ng build",
14 "test": "ng test",
15 "lint": "ng lint",
16 "e2e": "ng e2e"
17 },
18 "private": true,
19 "dependencies": {
20 "@angular-devkit/architect": "^0.1202.5",
21 "@angular-devkit/architect-cli": "^0.1202.5",
22 "@angular/common": "~12.1.1",
23 "@angular/core": "~12.1.1",
24 "@angular/fire": "^7.0.4",
25 "@angular/forms": "~12.1.1",
26 "@angular/platform-browser": "~12.1.1",
27 "@angular/platform-browser-dynamic": "~12.1.1",
28 "@angular/router": "~12.1.1",
29 "@ionic/angular": "^5.5.2",
30 "ajv": "^8.6.2",
31 "angularfire2": "^5.4.2",
32 "firebase": "^7.24.0",
33 "rxfire": "^6.0.0",
34 "rxjs": "~6.6.0",
35 "tslib": "^2.2.0",
36 "zone.js": "~0.11.4"
37 },
38 "devDependencies": {
39 "@angular-devkit/build-angular": "~12.1.1",
40 "@angular-eslint/builder": "~12.0.0",
41 "@angular-eslint/eslint-plugin": "~12.0.0",
42 "@angular-eslint/eslint-plugin-template": "~12.0.0",
43 "@angular-eslint/template-parser": "~12.0.0",
44 "@angular/cli": "~12.1.1",
45 "@angular/compiler": "~12.1.1",
46 "@angular/compiler-cli": "~12.1.1",
47 "@angular/language-service": "~12.0.1",
48 "@ionic/angular-toolkit": "^4.0.0",
49 "@types/jasmine": "~3.6.0",
50 "@types/jasminewd2": "~2.0.3",
51 "@types/node": "^12.11.1",
52 "@typescript-eslint/eslint-plugin": "4.16.1",
53 "@typescript-eslint/parser": "4.16.1",
54 "eslint": "^7.6.0",
55 "eslint-plugin-import": "2.22.1",
56 "eslint-plugin-jsdoc": "30.7.6",
57 "eslint-plugin-prefer-arrow": "1.2.2",
58 "jasmine-core": "~3.8.0",
59 "jasmine-spec-reporter": "~5.0.0",
60 "karma": "~6.3.2",
61 "karma-chrome-launcher": "~3.1.0",
62 "karma-coverage": "~2.0.3",
63 "karma-coverage-istanbul-reporter": "~3.0.2",
64 "karma-jasmine": "~4.0.0",
65 "karma-jasmine-html-reporter": "^1.5.0",
66 "protractor": "~7.0.0",
67 "ts-node": "~8.3.0",
68 "typescript": "~4.2.4",
69 "@angular-devkit/architect": "^0.1200.0",
70 "firebase-tools": "^9.0.0",
71 "fuzzy": "^0.1.3",
72 "inquirer": "^6.2.2",
73 "inquirer-autocomplete-prompt": "^1.0.1",
74 "open": "^7.0.3",
75 "jsonc-parser": "^3.0.0"
76 },
77 "description": "An Ionic project"
78}
79
And here is my app.module.ts:
1'"@angular/fire"' has no exported member 'AngularFireModule'.ts(2305),
2'"@angular/fire/storage"' has no exported member 'AngularFireStorageModule'.ts(2305)
3'"@angular/fire/database"' has no exported member 'AngularFireDatabaseModule'.ts(2305)
4'"@angular/fire/auth"' has no exported member 'AngularFireAuthModule'.ts(2305)
5{
6 "name": "gescable",
7 "version": "0.0.1",
8 "author": "Ionic Framework",
9 "homepage": "https://ionicframework.com/",
10 "scripts": {
11 "ng": "ng",
12 "start": "ng serve",
13 "build": "ng build",
14 "test": "ng test",
15 "lint": "ng lint",
16 "e2e": "ng e2e"
17 },
18 "private": true,
19 "dependencies": {
20 "@angular-devkit/architect": "^0.1202.5",
21 "@angular-devkit/architect-cli": "^0.1202.5",
22 "@angular/common": "~12.1.1",
23 "@angular/core": "~12.1.1",
24 "@angular/fire": "^7.0.4",
25 "@angular/forms": "~12.1.1",
26 "@angular/platform-browser": "~12.1.1",
27 "@angular/platform-browser-dynamic": "~12.1.1",
28 "@angular/router": "~12.1.1",
29 "@ionic/angular": "^5.5.2",
30 "ajv": "^8.6.2",
31 "angularfire2": "^5.4.2",
32 "firebase": "^7.24.0",
33 "rxfire": "^6.0.0",
34 "rxjs": "~6.6.0",
35 "tslib": "^2.2.0",
36 "zone.js": "~0.11.4"
37 },
38 "devDependencies": {
39 "@angular-devkit/build-angular": "~12.1.1",
40 "@angular-eslint/builder": "~12.0.0",
41 "@angular-eslint/eslint-plugin": "~12.0.0",
42 "@angular-eslint/eslint-plugin-template": "~12.0.0",
43 "@angular-eslint/template-parser": "~12.0.0",
44 "@angular/cli": "~12.1.1",
45 "@angular/compiler": "~12.1.1",
46 "@angular/compiler-cli": "~12.1.1",
47 "@angular/language-service": "~12.0.1",
48 "@ionic/angular-toolkit": "^4.0.0",
49 "@types/jasmine": "~3.6.0",
50 "@types/jasminewd2": "~2.0.3",
51 "@types/node": "^12.11.1",
52 "@typescript-eslint/eslint-plugin": "4.16.1",
53 "@typescript-eslint/parser": "4.16.1",
54 "eslint": "^7.6.0",
55 "eslint-plugin-import": "2.22.1",
56 "eslint-plugin-jsdoc": "30.7.6",
57 "eslint-plugin-prefer-arrow": "1.2.2",
58 "jasmine-core": "~3.8.0",
59 "jasmine-spec-reporter": "~5.0.0",
60 "karma": "~6.3.2",
61 "karma-chrome-launcher": "~3.1.0",
62 "karma-coverage": "~2.0.3",
63 "karma-coverage-istanbul-reporter": "~3.0.2",
64 "karma-jasmine": "~4.0.0",
65 "karma-jasmine-html-reporter": "^1.5.0",
66 "protractor": "~7.0.0",
67 "ts-node": "~8.3.0",
68 "typescript": "~4.2.4",
69 "@angular-devkit/architect": "^0.1200.0",
70 "firebase-tools": "^9.0.0",
71 "fuzzy": "^0.1.3",
72 "inquirer": "^6.2.2",
73 "inquirer-autocomplete-prompt": "^1.0.1",
74 "open": "^7.0.3",
75 "jsonc-parser": "^3.0.0"
76 },
77 "description": "An Ionic project"
78}
79import { NgModule } from '@angular/core';
80import { BrowserModule } from '@angular/platform-browser';
81import { RouteReuseStrategy } from '@angular/router';
82import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
83import { AppRoutingModule } from './app-routing.module';
84import { AppComponent } from './app.component';
85import { ClientPageModule } from './client/client.module';
86import { environment } from '../environments/environment';
87import { AngularFireModule } from '@angular/fire';
88import { AngularFireAuthModule } from '@angular/fire/auth';
89import { AngularFireStorageModule } from '@angular/fire/storage';
90import { AngularFireDatabaseModule } from '@angular/fire/database';
91
92@NgModule({
93 declarations: [AppComponent],
94 entryComponents: [],
95 imports: [
96 BrowserModule,
97 IonicModule.forRoot(),
98 AppRoutingModule,
99 ClientPageModule,
100 AngularFireModule.initializeApp(environment.firebaseConfig),
101 AngularFireAuthModule,
102 AngularFireStorageModule,
103 AngularFireDatabaseModule
104 ],
105 providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
106 bootstrap: [AppComponent],
107})
108export class AppModule {}
109
Here is my tsonfig.ts file
1'"@angular/fire"' has no exported member 'AngularFireModule'.ts(2305),
2'"@angular/fire/storage"' has no exported member 'AngularFireStorageModule'.ts(2305)
3'"@angular/fire/database"' has no exported member 'AngularFireDatabaseModule'.ts(2305)
4'"@angular/fire/auth"' has no exported member 'AngularFireAuthModule'.ts(2305)
5{
6 "name": "gescable",
7 "version": "0.0.1",
8 "author": "Ionic Framework",
9 "homepage": "https://ionicframework.com/",
10 "scripts": {
11 "ng": "ng",
12 "start": "ng serve",
13 "build": "ng build",
14 "test": "ng test",
15 "lint": "ng lint",
16 "e2e": "ng e2e"
17 },
18 "private": true,
19 "dependencies": {
20 "@angular-devkit/architect": "^0.1202.5",
21 "@angular-devkit/architect-cli": "^0.1202.5",
22 "@angular/common": "~12.1.1",
23 "@angular/core": "~12.1.1",
24 "@angular/fire": "^7.0.4",
25 "@angular/forms": "~12.1.1",
26 "@angular/platform-browser": "~12.1.1",
27 "@angular/platform-browser-dynamic": "~12.1.1",
28 "@angular/router": "~12.1.1",
29 "@ionic/angular": "^5.5.2",
30 "ajv": "^8.6.2",
31 "angularfire2": "^5.4.2",
32 "firebase": "^7.24.0",
33 "rxfire": "^6.0.0",
34 "rxjs": "~6.6.0",
35 "tslib": "^2.2.0",
36 "zone.js": "~0.11.4"
37 },
38 "devDependencies": {
39 "@angular-devkit/build-angular": "~12.1.1",
40 "@angular-eslint/builder": "~12.0.0",
41 "@angular-eslint/eslint-plugin": "~12.0.0",
42 "@angular-eslint/eslint-plugin-template": "~12.0.0",
43 "@angular-eslint/template-parser": "~12.0.0",
44 "@angular/cli": "~12.1.1",
45 "@angular/compiler": "~12.1.1",
46 "@angular/compiler-cli": "~12.1.1",
47 "@angular/language-service": "~12.0.1",
48 "@ionic/angular-toolkit": "^4.0.0",
49 "@types/jasmine": "~3.6.0",
50 "@types/jasminewd2": "~2.0.3",
51 "@types/node": "^12.11.1",
52 "@typescript-eslint/eslint-plugin": "4.16.1",
53 "@typescript-eslint/parser": "4.16.1",
54 "eslint": "^7.6.0",
55 "eslint-plugin-import": "2.22.1",
56 "eslint-plugin-jsdoc": "30.7.6",
57 "eslint-plugin-prefer-arrow": "1.2.2",
58 "jasmine-core": "~3.8.0",
59 "jasmine-spec-reporter": "~5.0.0",
60 "karma": "~6.3.2",
61 "karma-chrome-launcher": "~3.1.0",
62 "karma-coverage": "~2.0.3",
63 "karma-coverage-istanbul-reporter": "~3.0.2",
64 "karma-jasmine": "~4.0.0",
65 "karma-jasmine-html-reporter": "^1.5.0",
66 "protractor": "~7.0.0",
67 "ts-node": "~8.3.0",
68 "typescript": "~4.2.4",
69 "@angular-devkit/architect": "^0.1200.0",
70 "firebase-tools": "^9.0.0",
71 "fuzzy": "^0.1.3",
72 "inquirer": "^6.2.2",
73 "inquirer-autocomplete-prompt": "^1.0.1",
74 "open": "^7.0.3",
75 "jsonc-parser": "^3.0.0"
76 },
77 "description": "An Ionic project"
78}
79import { NgModule } from '@angular/core';
80import { BrowserModule } from '@angular/platform-browser';
81import { RouteReuseStrategy } from '@angular/router';
82import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
83import { AppRoutingModule } from './app-routing.module';
84import { AppComponent } from './app.component';
85import { ClientPageModule } from './client/client.module';
86import { environment } from '../environments/environment';
87import { AngularFireModule } from '@angular/fire';
88import { AngularFireAuthModule } from '@angular/fire/auth';
89import { AngularFireStorageModule } from '@angular/fire/storage';
90import { AngularFireDatabaseModule } from '@angular/fire/database';
91
92@NgModule({
93 declarations: [AppComponent],
94 entryComponents: [],
95 imports: [
96 BrowserModule,
97 IonicModule.forRoot(),
98 AppRoutingModule,
99 ClientPageModule,
100 AngularFireModule.initializeApp(environment.firebaseConfig),
101 AngularFireAuthModule,
102 AngularFireStorageModule,
103 AngularFireDatabaseModule
104 ],
105 providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
106 bootstrap: [AppComponent],
107})
108export class AppModule {}
109 "compileOnSave": false,
110 "compilerOptions": {
111 "baseUrl": "./",
112 "outDir": "./dist/out-tsc",
113 "sourceMap": true,
114 "declaration": false,
115 "downlevelIteration": true,
116 "experimentalDecorators": true,
117 "moduleResolution": "node",
118 "importHelpers": true,
119 "target": "es2015",
120 "module": "es2020",
121 "lib": ["es2018", "dom"]
122 },
123 "angularCompilerOptions": {
124 "enableI18nLegacyMessageIdFormat": false,
125 "strictInjectionParameters": true,
126 "strictInputAccessModifiers": true,
127 "strictTemplates": true,
128 "skipLibCheck": true
129 }
130}
131
ANSWER
Answered 2021-Sep-10 at 12:47You need to add "compat" like this
1'"@angular/fire"' has no exported member 'AngularFireModule'.ts(2305),
2'"@angular/fire/storage"' has no exported member 'AngularFireStorageModule'.ts(2305)
3'"@angular/fire/database"' has no exported member 'AngularFireDatabaseModule'.ts(2305)
4'"@angular/fire/auth"' has no exported member 'AngularFireAuthModule'.ts(2305)
5{
6 "name": "gescable",
7 "version": "0.0.1",
8 "author": "Ionic Framework",
9 "homepage": "https://ionicframework.com/",
10 "scripts": {
11 "ng": "ng",
12 "start": "ng serve",
13 "build": "ng build",
14 "test": "ng test",
15 "lint": "ng lint",
16 "e2e": "ng e2e"
17 },
18 "private": true,
19 "dependencies": {
20 "@angular-devkit/architect": "^0.1202.5",
21 "@angular-devkit/architect-cli": "^0.1202.5",
22 "@angular/common": "~12.1.1",
23 "@angular/core": "~12.1.1",
24 "@angular/fire": "^7.0.4",
25 "@angular/forms": "~12.1.1",
26 "@angular/platform-browser": "~12.1.1",
27 "@angular/platform-browser-dynamic": "~12.1.1",
28 "@angular/router": "~12.1.1",
29 "@ionic/angular": "^5.5.2",
30 "ajv": "^8.6.2",
31 "angularfire2": "^5.4.2",
32 "firebase": "^7.24.0",
33 "rxfire": "^6.0.0",
34 "rxjs": "~6.6.0",
35 "tslib": "^2.2.0",
36 "zone.js": "~0.11.4"
37 },
38 "devDependencies": {
39 "@angular-devkit/build-angular": "~12.1.1",
40 "@angular-eslint/builder": "~12.0.0",
41 "@angular-eslint/eslint-plugin": "~12.0.0",
42 "@angular-eslint/eslint-plugin-template": "~12.0.0",
43 "@angular-eslint/template-parser": "~12.0.0",
44 "@angular/cli": "~12.1.1",
45 "@angular/compiler": "~12.1.1",
46 "@angular/compiler-cli": "~12.1.1",
47 "@angular/language-service": "~12.0.1",
48 "@ionic/angular-toolkit": "^4.0.0",
49 "@types/jasmine": "~3.6.0",
50 "@types/jasminewd2": "~2.0.3",
51 "@types/node": "^12.11.1",
52 "@typescript-eslint/eslint-plugin": "4.16.1",
53 "@typescript-eslint/parser": "4.16.1",
54 "eslint": "^7.6.0",
55 "eslint-plugin-import": "2.22.1",
56 "eslint-plugin-jsdoc": "30.7.6",
57 "eslint-plugin-prefer-arrow": "1.2.2",
58 "jasmine-core": "~3.8.0",
59 "jasmine-spec-reporter": "~5.0.0",
60 "karma": "~6.3.2",
61 "karma-chrome-launcher": "~3.1.0",
62 "karma-coverage": "~2.0.3",
63 "karma-coverage-istanbul-reporter": "~3.0.2",
64 "karma-jasmine": "~4.0.0",
65 "karma-jasmine-html-reporter": "^1.5.0",
66 "protractor": "~7.0.0",
67 "ts-node": "~8.3.0",
68 "typescript": "~4.2.4",
69 "@angular-devkit/architect": "^0.1200.0",
70 "firebase-tools": "^9.0.0",
71 "fuzzy": "^0.1.3",
72 "inquirer": "^6.2.2",
73 "inquirer-autocomplete-prompt": "^1.0.1",
74 "open": "^7.0.3",
75 "jsonc-parser": "^3.0.0"
76 },
77 "description": "An Ionic project"
78}
79import { NgModule } from '@angular/core';
80import { BrowserModule } from '@angular/platform-browser';
81import { RouteReuseStrategy } from '@angular/router';
82import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
83import { AppRoutingModule } from './app-routing.module';
84import { AppComponent } from './app.component';
85import { ClientPageModule } from './client/client.module';
86import { environment } from '../environments/environment';
87import { AngularFireModule } from '@angular/fire';
88import { AngularFireAuthModule } from '@angular/fire/auth';
89import { AngularFireStorageModule } from '@angular/fire/storage';
90import { AngularFireDatabaseModule } from '@angular/fire/database';
91
92@NgModule({
93 declarations: [AppComponent],
94 entryComponents: [],
95 imports: [
96 BrowserModule,
97 IonicModule.forRoot(),
98 AppRoutingModule,
99 ClientPageModule,
100 AngularFireModule.initializeApp(environment.firebaseConfig),
101 AngularFireAuthModule,
102 AngularFireStorageModule,
103 AngularFireDatabaseModule
104 ],
105 providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
106 bootstrap: [AppComponent],
107})
108export class AppModule {}
109 "compileOnSave": false,
110 "compilerOptions": {
111 "baseUrl": "./",
112 "outDir": "./dist/out-tsc",
113 "sourceMap": true,
114 "declaration": false,
115 "downlevelIteration": true,
116 "experimentalDecorators": true,
117 "moduleResolution": "node",
118 "importHelpers": true,
119 "target": "es2015",
120 "module": "es2020",
121 "lib": ["es2018", "dom"]
122 },
123 "angularCompilerOptions": {
124 "enableI18nLegacyMessageIdFormat": false,
125 "strictInjectionParameters": true,
126 "strictInputAccessModifiers": true,
127 "strictTemplates": true,
128 "skipLibCheck": true
129 }
130}
131import { AngularFireModule } from "@angular/fire/compat";
132import { AngularFireAuthModule } from "@angular/fire/compat/auth";
133import { AngularFireStorageModule } from '@angular/fire/compat/storage';
134import { AngularFirestoreModule } from '@angular/fire/compat/firestore';
135import { AngularFireDatabaseModule } from '@angular/fire/compat/database';
136
QUESTION
Module not found: Error: Can't resolve 'date-fns/addDays' in 'C:\Users\
Asked 2022-Feb-08 at 17:19I want to use Date picker from MUI but I get this error and I don't know what exactly is wrong. here is my code:
1import TextField from "@mui/material/TextField";
2import DatePicker from "@mui/lab/DatePicker";
3import AdapterDateFns from "@mui/lab/AdapterDateFns";
4import LocalizationProvider from "@mui/lab/LocalizationProvider";
5
6const ExpenseForm = () => {
7 return (
8 <Box component="form" noValidate autoComplete="off">
9 <LocalizationProvider dateAdapter={AdapterDateFns}>
10 <DatePicker
11 label="Basic example"
12 onChange={(newValue) => {}}
13 renderInput={(params) => <TextField {...params} />}
14 />
15 </LocalizationProvider>
16 </Box>
17 );
18};
19
20export default ExpenseForm;
21
and my package.json:
1import TextField from "@mui/material/TextField";
2import DatePicker from "@mui/lab/DatePicker";
3import AdapterDateFns from "@mui/lab/AdapterDateFns";
4import LocalizationProvider from "@mui/lab/LocalizationProvider";
5
6const ExpenseForm = () => {
7 return (
8 <Box component="form" noValidate autoComplete="off">
9 <LocalizationProvider dateAdapter={AdapterDateFns}>
10 <DatePicker
11 label="Basic example"
12 onChange={(newValue) => {}}
13 renderInput={(params) => <TextField {...params} />}
14 />
15 </LocalizationProvider>
16 </Box>
17 );
18};
19
20export default ExpenseForm;
21"dependencies": {
22 "@date-io/date-fns": "^2.13.1",
23 "@emotion/react": "^11.7.1",
24 "@emotion/styled": "^11.6.0",
25 "@mui/icons-material": "^5.3.1",
26 "@mui/lab": "^5.0.0-alpha.68",
27 "@mui/material": "^5.4.0",
28 "@testing-library/jest-dom": "^5.16.1",
29 "@testing-library/react": "^12.1.2",
30 "@testing-library/user-event": "^13.5.0",
31 "react": "^17.0.2",
32 "react-dom": "^17.0.2",
33 "react-scripts": "5.0.0",
34 "web-vitals": "^2.1.4"
35 },
36
but everytime I get these errors:
1import TextField from "@mui/material/TextField";
2import DatePicker from "@mui/lab/DatePicker";
3import AdapterDateFns from "@mui/lab/AdapterDateFns";
4import LocalizationProvider from "@mui/lab/LocalizationProvider";
5
6const ExpenseForm = () => {
7 return (
8 <Box component="form" noValidate autoComplete="off">
9 <LocalizationProvider dateAdapter={AdapterDateFns}>
10 <DatePicker
11 label="Basic example"
12 onChange={(newValue) => {}}
13 renderInput={(params) => <TextField {...params} />}
14 />
15 </LocalizationProvider>
16 </Box>
17 );
18};
19
20export default ExpenseForm;
21"dependencies": {
22 "@date-io/date-fns": "^2.13.1",
23 "@emotion/react": "^11.7.1",
24 "@emotion/styled": "^11.6.0",
25 "@mui/icons-material": "^5.3.1",
26 "@mui/lab": "^5.0.0-alpha.68",
27 "@mui/material": "^5.4.0",
28 "@testing-library/jest-dom": "^5.16.1",
29 "@testing-library/react": "^12.1.2",
30 "@testing-library/user-event": "^13.5.0",
31 "react": "^17.0.2",
32 "react-dom": "^17.0.2",
33 "react-scripts": "5.0.0",
34 "web-vitals": "^2.1.4"
35 },
36Compiled with problems:
37
38ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 1:0-39
39
40Module not found: Error: Can't resolve 'date-fns/addDays' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
41
42
43ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 2:0-45
44
45Module not found: Error: Can't resolve 'date-fns/addSeconds' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
46
47
48ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 3:0-45
49
50Module not found: Error: Can't resolve 'date-fns/addMinutes' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
51
52
53ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 4:0-41
54
55Module not found: Error: Can't resolve 'date-fns/addHours' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
56
57
58ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 5:0-41
59
60Module not found: Error: Can't resolve 'date-fns/addWeeks' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
61
62
63ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 6:0-43
64
65Module not found: Error: Can't resolve 'date-fns/addMonths' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
66
67
68ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 7:0-41
69
70Module not found: Error: Can't resolve 'date-fns/addYears' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
71
72
73ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 8:0-59
74
75Module not found: Error: Can't resolve 'date-fns/differenceInYears' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
76
77
78ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 9:0-65
79
80Module not found: Error: Can't resolve 'date-fns/differenceInQuarters' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
81
82
83ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 10:0-61
84
85Module not found: Error: Can't resolve 'date-fns/differenceInMonths' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
86
87
88ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 11:0-59
89
90Module not found: Error: Can't resolve 'date-fns/differenceInWeeks' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
91
92
93ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 12:0-57
94
95Module not found: Error: Can't resolve 'date-fns/differenceInDays' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
96
97
98ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 13:0-59
99
100Module not found: Error: Can't resolve 'date-fns/differenceInHours' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
101
102
103ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 14:0-63
104
105Module not found: Error: Can't resolve 'date-fns/differenceInMinutes' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
106
107
108ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 15:0-63
109
110Module not found: Error: Can't resolve 'date-fns/differenceInSeconds' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
111
112
113ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 16:0-73
114
115Module not found: Error: Can't resolve 'date-fns/differenceInMilliseconds' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
116
117
118ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 17:0-59
119
120Module not found: Error: Can't resolve 'date-fns/eachDayOfInterval' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
121
122
123ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 18:0-41
124
125Module not found: Error: Can't resolve 'date-fns/endOfDay' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
126
127
128ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 19:0-43
129
130Module not found: Error: Can't resolve 'date-fns/endOfWeek' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
131
132
133ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 20:0-43
134
135Module not found: Error: Can't resolve 'date-fns/endOfYear' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
136
137
138ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 21:0-37
139
140Module not found: Error: Can't resolve 'date-fns/format' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
141
142
143ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 22:0-41
144
145Module not found: Error: Can't resolve 'date-fns/getHours' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
146
147
148ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 23:0-45
149
150Module not found: Error: Can't resolve 'date-fns/getSeconds' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
151
152
153ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 24:0-39
154
155Module not found: Error: Can't resolve 'date-fns/getYear' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
156
157
158ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 25:0-39
159
160Module not found: Error: Can't resolve 'date-fns/isAfter' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
161
162
163ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 26:0-41
164
165Module not found: Error: Can't resolve 'date-fns/isBefore' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
166
167
168ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 27:0-39
169
170Module not found: Error: Can't resolve 'date-fns/isEqual' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
171
172
173ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 28:0-43
174
175Module not found: Error: Can't resolve 'date-fns/isSameDay' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
176
177
178ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 29:0-45
179
180Module not found: Error: Can't resolve 'date-fns/isSameYear' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
181
182
183ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 30:0-47
184
185Module not found: Error: Can't resolve 'date-fns/isSameMonth' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
186
187
188ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 31:0-45
189
190Module not found: Error: Can't resolve 'date-fns/isSameHour' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
191
192
193ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 32:0-39
194
195Module not found: Error: Can't resolve 'date-fns/isValid' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
196
197
198ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 33:0-42
199
200Module not found: Error: Can't resolve 'date-fns/parse' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
201
202
203ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 34:0-41
204
205Module not found: Error: Can't resolve 'date-fns/setHours' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
206
207
208ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 35:0-45
209
210Module not found: Error: Can't resolve 'date-fns/setMinutes' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
211
212
213ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 36:0-41
214
215Module not found: Error: Can't resolve 'date-fns/setMonth' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
216
217
218ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 37:0-37
219
220Module not found: Error: Can't resolve 'date-fns/getDay' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
221
222
223ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 38:0-53
224
225Module not found: Error: Can't resolve 'date-fns/getDaysInMonth' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
226
227
228ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 39:0-45
229
230Module not found: Error: Can't resolve 'date-fns/setSeconds' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
231
232
233ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 40:0-39
234
235Module not found: Error: Can't resolve 'date-fns/setYear' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
236
237
238ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 41:0-45
239
240Module not found: Error: Can't resolve 'date-fns/startOfDay' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
241
242
243ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 42:0-49
244
245Module not found: Error: Can't resolve 'date-fns/startOfMonth' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
246
247
248ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 43:0-45
249
250Module not found: Error: Can't resolve 'date-fns/endOfMonth' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
251
252
253ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 44:0-47
254
255Module not found: Error: Can't resolve 'date-fns/startOfWeek' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
256
257
258ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 45:0-47
259
260Module not found: Error: Can't resolve 'date-fns/startOfYear' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
261
262
263ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 46:0-41
264
265Module not found: Error: Can't resolve 'date-fns/parseISO' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
266
267
268ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 47:0-43
269
270Module not found: Error: Can't resolve 'date-fns/formatISO' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
271
272
273ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 48:0-57
274
275Module not found: Error: Can't resolve 'date-fns/isWithinInterval' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
276
277
278ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 49:0-65
279
280Module not found: Error: Can't resolve 'date-fns/_lib/format/longFormatters' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
281
282
283ERROR in ./node_modules/@date-io/date-fns/build/index.esm.js 50:0-50
284
285Module not found: Error: Can't resolve 'date-fns/locale/en-US' in 'C:\Users\Amir\Desktop\React\React-apps\expense-tracker\node_modules\@date-io\date-fns\build'
286
I searched the web but couldn't find something useful . also some StackOverflow similar posts that suggested to restart the server I tried but didn't actually solve my problem.
ANSWER
Answered 2022-Feb-08 at 17:19You need to install the date-fns
package from NPM using npm install --save date-fns
.
QUESTION
Simulate Bash's COMPREPLY response without actually completing it
Asked 2022-Feb-07 at 12:22Create directory on tmp, add 1 file inside.
1mkdir /tmp/testdir && touch /tmp/testdir/examplefile
2
Paste below script on /tmp/completion.sh
1mkdir /tmp/testdir && touch /tmp/testdir/examplefile
2# BEGIN AUTOCOMPLETE
3function _foo_complete() {
4local comnum cur opts
5[[ "${COMP_WORDS[@]}" == *"-"* ]] && comnum=2 || comnum=1;
6COMPREPLY=()
7cur="${COMP_WORDS[COMP_CWORD]}"
8opts="--help --restart -h -r"
9if (( COMP_CWORD > comnum )); then
10 COMPREPLY=( $(for filename in "/tmp/testdir/"*; do echo ${filename##*/}; done) )
11 return
12fi
13if [[ ${cur} == -* ]]; then
14 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
15 return 0
16else
17 COMPREPLY=( $(for filelist in /tmp/testdir/"$2"*; do echo ${filelist##*/}; done) )
18fi
19}
20complete -F _foo_complete foo.sh
21# END AUTOCOMPLETE
22
Source it then.
1mkdir /tmp/testdir && touch /tmp/testdir/examplefile
2# BEGIN AUTOCOMPLETE
3function _foo_complete() {
4local comnum cur opts
5[[ "${COMP_WORDS[@]}" == *"-"* ]] && comnum=2 || comnum=1;
6COMPREPLY=()
7cur="${COMP_WORDS[COMP_CWORD]}"
8opts="--help --restart -h -r"
9if (( COMP_CWORD > comnum )); then
10 COMPREPLY=( $(for filename in "/tmp/testdir/"*; do echo ${filename##*/}; done) )
11 return
12fi
13if [[ ${cur} == -* ]]; then
14 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
15 return 0
16else
17 COMPREPLY=( $(for filelist in /tmp/testdir/"$2"*; do echo ${filelist##*/}; done) )
18fi
19}
20complete -F _foo_complete foo.sh
21# END AUTOCOMPLETE
22. /tmp/completion.sh
23
Expected result
1mkdir /tmp/testdir && touch /tmp/testdir/examplefile
2# BEGIN AUTOCOMPLETE
3function _foo_complete() {
4local comnum cur opts
5[[ "${COMP_WORDS[@]}" == *"-"* ]] && comnum=2 || comnum=1;
6COMPREPLY=()
7cur="${COMP_WORDS[COMP_CWORD]}"
8opts="--help --restart -h -r"
9if (( COMP_CWORD > comnum )); then
10 COMPREPLY=( $(for filename in "/tmp/testdir/"*; do echo ${filename##*/}; done) )
11 return
12fi
13if [[ ${cur} == -* ]]; then
14 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
15 return 0
16else
17 COMPREPLY=( $(for filelist in /tmp/testdir/"$2"*; do echo ${filelist##*/}; done) )
18fi
19}
20complete -F _foo_complete foo.sh
21# END AUTOCOMPLETE
22. /tmp/completion.sh
23$ foo.sh --restart examplefile <tab><tab>
24examplefile
25$ foo.sh --restart examplefile <tab><tab>
26examplefile
27$ foo.sh --restart examplefile <tab><tab>
28examplefile
29$ foo.sh --restart examplefile <tab><tab>
30
1mkdir /tmp/testdir && touch /tmp/testdir/examplefile
2# BEGIN AUTOCOMPLETE
3function _foo_complete() {
4local comnum cur opts
5[[ "${COMP_WORDS[@]}" == *"-"* ]] && comnum=2 || comnum=1;
6COMPREPLY=()
7cur="${COMP_WORDS[COMP_CWORD]}"
8opts="--help --restart -h -r"
9if (( COMP_CWORD > comnum )); then
10 COMPREPLY=( $(for filename in "/tmp/testdir/"*; do echo ${filename##*/}; done) )
11 return
12fi
13if [[ ${cur} == -* ]]; then
14 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
15 return 0
16else
17 COMPREPLY=( $(for filelist in /tmp/testdir/"$2"*; do echo ${filelist##*/}; done) )
18fi
19}
20complete -F _foo_complete foo.sh
21# END AUTOCOMPLETE
22. /tmp/completion.sh
23$ foo.sh --restart examplefile <tab><tab>
24examplefile
25$ foo.sh --restart examplefile <tab><tab>
26examplefile
27$ foo.sh --restart examplefile <tab><tab>
28examplefile
29$ foo.sh --restart examplefile <tab><tab>
30$ foo.sh --restart examplefile <tab><tab> examplefile <tab><tab> examplefile <tab><tab> examplefile <tab><tab> examplefile <tab><tab> examplefile
31
I want the suggestion to appear as possible completion, but without actually completing it (for display purposes). This question has been asked before, but to this date no answer is given.
Regarding-o nosort
I look into that option and it's only available at Bash 4.4+, I tried on my 16.04 machine and it fail. Looking for more globalish solution
ANSWER
Answered 2022-Jan-09 at 13:05Try the following compspec.sh
(based on OP's code):
1mkdir /tmp/testdir && touch /tmp/testdir/examplefile
2# BEGIN AUTOCOMPLETE
3function _foo_complete() {
4local comnum cur opts
5[[ "${COMP_WORDS[@]}" == *"-"* ]] && comnum=2 || comnum=1;
6COMPREPLY=()
7cur="${COMP_WORDS[COMP_CWORD]}"
8opts="--help --restart -h -r"
9if (( COMP_CWORD > comnum )); then
10 COMPREPLY=( $(for filename in "/tmp/testdir/"*; do echo ${filename##*/}; done) )
11 return
12fi
13if [[ ${cur} == -* ]]; then
14 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
15 return 0
16else
17 COMPREPLY=( $(for filelist in /tmp/testdir/"$2"*; do echo ${filelist##*/}; done) )
18fi
19}
20complete -F _foo_complete foo.sh
21# END AUTOCOMPLETE
22. /tmp/completion.sh
23$ foo.sh --restart examplefile <tab><tab>
24examplefile
25$ foo.sh --restart examplefile <tab><tab>
26examplefile
27$ foo.sh --restart examplefile <tab><tab>
28examplefile
29$ foo.sh --restart examplefile <tab><tab>
30$ foo.sh --restart examplefile <tab><tab> examplefile <tab><tab> examplefile <tab><tab> examplefile <tab><tab> examplefile <tab><tab> examplefile
31function _foo_complete()
32{
33 local comnum cur opts
34
35 [[ "${COMP_WORDS[@]}" == *"-"* ]] && comnum=2 || comnum=1;
36
37 COMPREPLY=()
38 cur="${COMP_WORDS[COMP_CWORD]}"
39 opts="--help --restart -h -r"
40
41 if (( COMP_CWORD > comnum )); then
42 COMPREPLY=( $(for filename in "/tmp/testdir/"*; do echo ${filename##*/}; done) )
43 if [[ ${#COMPREPLY[@]} -gt 0 ]]; then
44 #
45 # you can try COMPREPLY+=( zzz ) and see what's happening
46 #
47 COMPREPLY+=( ' ' )
48 fi
49 return
50 fi
51
52 if [[ ${cur} == -* ]]; then
53 COMPREPLY=( $( compgen -W "${opts}" -- ${cur} ) )
54 return 0
55 else
56 COMPREPLY=( $( for filelist in /tmp/testdir/"$2"*; do echo ${filelist##*/}; done ) )
57 fi
58}
59
60complete -F _foo_complete foo.sh
61
UPDATE:
is it possible to move the empty string to end of completion, so it doesn't look like there are empty space?
You can use complete -o nosort
(requires Bash 4.4+) if you can sort the completion candidates all by yourself.
QUESTION
React/Socket.io not displaying latest message passed down as prop
Asked 2022-Jan-13 at 17:37I am working on a chat application using React and socket.io. Back end is express/node. The relevant components are: Room.js --> Chat.js --> Messages.js --> Message.js
messageData received from the server is stored in state in Room.js. It is then passed down through Chat.js to Messages.js, where it is mapped onto a series of Message.js components.
When messages are received, they ARE appearing, but only after I start typing in the form again, triggering messageChangeHandler(). Any ideas why the Messages won't re-render when a new message is received and added to state in Room.js? I have confirmed that the state and props are updating everywhere they should be--they just aren't appearing/re-rendering until messageChangeHandler() triggers its own re-render.
Here are the components.
Room.js
1export default function Room(props) {
2 const [messagesData, setMessagesData] = useState([])
3
4 useEffect(() => {
5 console.log('the use effect ')
6 socket.on('broadcast', data => {
7 console.log(messagesData)
8 let previousData = messagesData
9 previousData.push(data)
10 // buildMessages(previousData)
11 setMessagesData(previousData)
12 })
13 }, [socket])
14
15
16 console.log('this is messagesData in queue.js', messagesData)
17
18 return(
19 // queue counter will go up here
20 // <QueueDisplay />
21
22 // chat goes here
23 <Chat
24 profile={props.profile}
25 messagesData={messagesData}
26 />
27
28 )
29}
30
Chat.js
1export default function Room(props) {
2 const [messagesData, setMessagesData] = useState([])
3
4 useEffect(() => {
5 console.log('the use effect ')
6 socket.on('broadcast', data => {
7 console.log(messagesData)
8 let previousData = messagesData
9 previousData.push(data)
10 // buildMessages(previousData)
11 setMessagesData(previousData)
12 })
13 }, [socket])
14
15
16 console.log('this is messagesData in queue.js', messagesData)
17
18 return(
19 // queue counter will go up here
20 // <QueueDisplay />
21
22 // chat goes here
23 <Chat
24 profile={props.profile}
25 messagesData={messagesData}
26 />
27
28 )
29}
30export default function Chat(props) {
31 // state
32 const [newPayload, setNewPayload] = useState({
33 message: '',
34 sender: props.profile.name
35 })
36 // const [messagesData, setMessagesData] = useState([])
37 const [updateToggle, setUpdateToggle] = useState(true)
38
39
40 const messageChangeHandler = (e) => {
41 setNewPayload({... newPayload, [e.target.name]: e.target.value})
42 }
43
44 const messageSend = (e) => {
45 e.preventDefault()
46 if (newPayload.message) {
47 socket.emit('chat message', newPayload)
48 setNewPayload({
49 message: '',
50 sender: props.profile.name
51 })
52 }
53 }
54
55 return(
56 <div id='chatbox'>
57 <div id='messages'>
58 <Messages messagesData={props.messagesData} />
59 </div>
60 <form onSubmit={messageSend}>
61 <input
62 type="text"
63 name="message"
64 id="message"
65 placeholder="Start a new message"
66 onChange={messageChangeHandler}
67 value={newPayload.message}
68 autoComplete='off'
69 />
70 <input type="submit" value="Send" />
71 </form>
72 </div>
73 )
74}
75
Messages.js
1export default function Room(props) {
2 const [messagesData, setMessagesData] = useState([])
3
4 useEffect(() => {
5 console.log('the use effect ')
6 socket.on('broadcast', data => {
7 console.log(messagesData)
8 let previousData = messagesData
9 previousData.push(data)
10 // buildMessages(previousData)
11 setMessagesData(previousData)
12 })
13 }, [socket])
14
15
16 console.log('this is messagesData in queue.js', messagesData)
17
18 return(
19 // queue counter will go up here
20 // <QueueDisplay />
21
22 // chat goes here
23 <Chat
24 profile={props.profile}
25 messagesData={messagesData}
26 />
27
28 )
29}
30export default function Chat(props) {
31 // state
32 const [newPayload, setNewPayload] = useState({
33 message: '',
34 sender: props.profile.name
35 })
36 // const [messagesData, setMessagesData] = useState([])
37 const [updateToggle, setUpdateToggle] = useState(true)
38
39
40 const messageChangeHandler = (e) => {
41 setNewPayload({... newPayload, [e.target.name]: e.target.value})
42 }
43
44 const messageSend = (e) => {
45 e.preventDefault()
46 if (newPayload.message) {
47 socket.emit('chat message', newPayload)
48 setNewPayload({
49 message: '',
50 sender: props.profile.name
51 })
52 }
53 }
54
55 return(
56 <div id='chatbox'>
57 <div id='messages'>
58 <Messages messagesData={props.messagesData} />
59 </div>
60 <form onSubmit={messageSend}>
61 <input
62 type="text"
63 name="message"
64 id="message"
65 placeholder="Start a new message"
66 onChange={messageChangeHandler}
67 value={newPayload.message}
68 autoComplete='off'
69 />
70 <input type="submit" value="Send" />
71 </form>
72 </div>
73 )
74}
75export default function Messages(props) {
76 return(
77 <>
78 {props.messagesData.map((data, i) => {
79 return <Message key={i} sender={data.sender} message={data.message} />
80 })}
81 </>
82 )
83}
84
Message.js
1export default function Room(props) {
2 const [messagesData, setMessagesData] = useState([])
3
4 useEffect(() => {
5 console.log('the use effect ')
6 socket.on('broadcast', data => {
7 console.log(messagesData)
8 let previousData = messagesData
9 previousData.push(data)
10 // buildMessages(previousData)
11 setMessagesData(previousData)
12 })
13 }, [socket])
14
15
16 console.log('this is messagesData in queue.js', messagesData)
17
18 return(
19 // queue counter will go up here
20 // <QueueDisplay />
21
22 // chat goes here
23 <Chat
24 profile={props.profile}
25 messagesData={messagesData}
26 />
27
28 )
29}
30export default function Chat(props) {
31 // state
32 const [newPayload, setNewPayload] = useState({
33 message: '',
34 sender: props.profile.name
35 })
36 // const [messagesData, setMessagesData] = useState([])
37 const [updateToggle, setUpdateToggle] = useState(true)
38
39
40 const messageChangeHandler = (e) => {
41 setNewPayload({... newPayload, [e.target.name]: e.target.value})
42 }
43
44 const messageSend = (e) => {
45 e.preventDefault()
46 if (newPayload.message) {
47 socket.emit('chat message', newPayload)
48 setNewPayload({
49 message: '',
50 sender: props.profile.name
51 })
52 }
53 }
54
55 return(
56 <div id='chatbox'>
57 <div id='messages'>
58 <Messages messagesData={props.messagesData} />
59 </div>
60 <form onSubmit={messageSend}>
61 <input
62 type="text"
63 name="message"
64 id="message"
65 placeholder="Start a new message"
66 onChange={messageChangeHandler}
67 value={newPayload.message}
68 autoComplete='off'
69 />
70 <input type="submit" value="Send" />
71 </form>
72 </div>
73 )
74}
75export default function Messages(props) {
76 return(
77 <>
78 {props.messagesData.map((data, i) => {
79 return <Message key={i} sender={data.sender} message={data.message} />
80 })}
81 </>
82 )
83}
84export default function Message(props) {
85 return(
86 <div key={props.key}>
87 <p>{props.sender}</p>
88 <p>{props.message}</p>
89 </div>
90 )
91}
92
Thank you in advance for any help!
ANSWER
Answered 2022-Jan-11 at 19:44Changing the useEffect in room to contain the following fixed the issue:
1export default function Room(props) {
2 const [messagesData, setMessagesData] = useState([])
3
4 useEffect(() => {
5 console.log('the use effect ')
6 socket.on('broadcast', data => {
7 console.log(messagesData)
8 let previousData = messagesData
9 previousData.push(data)
10 // buildMessages(previousData)
11 setMessagesData(previousData)
12 })
13 }, [socket])
14
15
16 console.log('this is messagesData in queue.js', messagesData)
17
18 return(
19 // queue counter will go up here
20 // <QueueDisplay />
21
22 // chat goes here
23 <Chat
24 profile={props.profile}
25 messagesData={messagesData}
26 />
27
28 )
29}
30export default function Chat(props) {
31 // state
32 const [newPayload, setNewPayload] = useState({
33 message: '',
34 sender: props.profile.name
35 })
36 // const [messagesData, setMessagesData] = useState([])
37 const [updateToggle, setUpdateToggle] = useState(true)
38
39
40 const messageChangeHandler = (e) => {
41 setNewPayload({... newPayload, [e.target.name]: e.target.value})
42 }
43
44 const messageSend = (e) => {
45 e.preventDefault()
46 if (newPayload.message) {
47 socket.emit('chat message', newPayload)
48 setNewPayload({
49 message: '',
50 sender: props.profile.name
51 })
52 }
53 }
54
55 return(
56 <div id='chatbox'>
57 <div id='messages'>
58 <Messages messagesData={props.messagesData} />
59 </div>
60 <form onSubmit={messageSend}>
61 <input
62 type="text"
63 name="message"
64 id="message"
65 placeholder="Start a new message"
66 onChange={messageChangeHandler}
67 value={newPayload.message}
68 autoComplete='off'
69 />
70 <input type="submit" value="Send" />
71 </form>
72 </div>
73 )
74}
75export default function Messages(props) {
76 return(
77 <>
78 {props.messagesData.map((data, i) => {
79 return <Message key={i} sender={data.sender} message={data.message} />
80 })}
81 </>
82 )
83}
84export default function Message(props) {
85 return(
86 <div key={props.key}>
87 <p>{props.sender}</p>
88 <p>{props.message}</p>
89 </div>
90 )
91}
92 useEffect(() => {
93 console.log('the use effect ')
94 socket.on('broadcast', data => {
95 console.log(messagesData)
96 // let previousData = messagesData
97 // previousData.push(data)
98 // setMessagesData(previousData)
99 setMessagesData(prev => prev.concat([data]))
100 })
101 }, [socket])```
102
QUESTION
Unable to build and deploy Rails 6.0.4.1 app on heroku - Throws gyp verb cli error
Asked 2022-Jan-02 at 10:07Hi i was deploying a branch on heroku and threw up this error. I also tried deploying a branch which worked perfectly, but that is also showing the same error.
local yarn verion : 1.22.17 local node version : v12.22.7 Please help !!!
Tried building without yarn.lock and package-lock same thing.
This is how it starts Heroku deployment build log through CLI
1yarn install v1.22.17
2remote: warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json.
3remote: [1/5] Validating package.json...
4remote: [2/5] Resolving packages...
5remote: [3/5] Fetching packages...
6remote: [4/5] Linking dependencies...
7remote: warning " > webpack-dev-server@4.6.0" has unmet peer dependency "webpack@^4.37.0 || ^5.0.0".
8remote: warning "webpack-dev-server > webpack-dev-middleware@5.2.1" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
9remote: [5/5] Building fresh packages...
10remote: error /tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-sass: Command failed.
11remote: Exit code: 1
12remote: Command: node scripts/build.js
13remote: Arguments:
14remote: Directory: /tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-sass
15remote: Output:
16remote: Building: /tmp/build_df192222/bin/node /tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-gyp/bin/node-gyp.js rebuild --verbose --libsass_ext= --libsass_cflags= --libsass_ldflags= --libsass_library=
17remote: gyp info it worked if it ends with ok
18remote: gyp verb cli [
19remote: gyp verb cli '/tmp/build_df192222/bin/node',
20remote: gyp verb cli '/tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-gyp/bin/node-gyp.js',
21remote: gyp verb cli 'rebuild',
22
. . . . . `
1yarn install v1.22.17
2remote: warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json.
3remote: [1/5] Validating package.json...
4remote: [2/5] Resolving packages...
5remote: [3/5] Fetching packages...
6remote: [4/5] Linking dependencies...
7remote: warning " > webpack-dev-server@4.6.0" has unmet peer dependency "webpack@^4.37.0 || ^5.0.0".
8remote: warning "webpack-dev-server > webpack-dev-middleware@5.2.1" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
9remote: [5/5] Building fresh packages...
10remote: error /tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-sass: Command failed.
11remote: Exit code: 1
12remote: Command: node scripts/build.js
13remote: Arguments:
14remote: Directory: /tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-sass
15remote: Output:
16remote: Building: /tmp/build_df192222/bin/node /tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-gyp/bin/node-gyp.js rebuild --verbose --libsass_ext= --libsass_cflags= --libsass_ldflags= --libsass_library=
17remote: gyp info it worked if it ends with ok
18remote: gyp verb cli [
19remote: gyp verb cli '/tmp/build_df192222/bin/node',
20remote: gyp verb cli '/tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-gyp/bin/node-gyp.js',
21remote: gyp verb cli 'rebuild',
22remote: /app/.node-gyp/16.13.1/include/node/v8-internal.h: In function ‘void v8::internal::PerformCastCheck(T*)’:
23remote: /app/.node-gyp/16.13.1/include/node/v8-internal.h:492:38: error: ‘remove_cv_t’ is not a member of ‘std’; did you mean ‘remove_cv’?
24remote: 492 | !std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data);
25remote: | ^~~~~~~~~~~
26remote: | remove_cv
27remote: /app/.node-gyp/16.13.1/include/node/v8-internal.h:492:38: error: ‘remove_cv_t’ is not a member of ‘std’; did you mean ‘remove_cv’?
28remote: 492 | !std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data);
29remote: | ^~~~~~~~~~~
30remote: | remove_cv
31remote: /app/.node-gyp/16.13.1/include/node/v8-internal.h:492:50: error: template argument 2 is invalid
32remote: 492 | !std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data);
33remote: | ^
34remote: /app/.node-gyp/16.13.1/include/node/v8-internal.h:492:63: error: ‘::Perform’ has not been declared
35remote: 492 | !std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data);
36remote: | ^~~~~~~
37remote: ../src/binding.cpp: In function ‘Nan::NAN_METHOD_RETURN_TYPE render(Nan::NAN_METHOD_ARGS_TYPE)’:
38remote: ../src/binding.cpp:284:98: warning: cast between incompatible function types from ‘void (*)(uv_work_t*)’ {aka ‘void (*)(uv_work_s*)’} to ‘uv_after_work_cb’ {aka ‘void (*)(uv_work_s*, int)’} [-Wcast-function-type]
39remote: 284 | int status = uv_queue_work(uv_default_loop(), &ctx_w->request, compile_it, (uv_after_work_cb)MakeCallback);
40remote: | ^~~~~~~~~~~~
41remote: ../src/binding.cpp: In function ‘Nan::NAN_METHOD_RETURN_TYPE render_file(Nan::NAN_METHOD_ARGS_TYPE)’:
42remote: ../src/binding.cpp:320:98: warning: cast between incompatible function types from ‘void (*)(uv_work_t*)’ {aka ‘void (*)(uv_work_s*)’} to ‘uv_after_work_cb’ {aka ‘void (*)(uv_work_s*, int)’} [-Wcast-function-type]
43remote: 320 | int status = uv_queue_work(uv_default_loop(), &ctx_w->request, compile_it, (uv_after_work_cb)MakeCallback);
44remote: | ^~~~~~~~~~~~
45remote: In file included from ../../../../../nan/nan.h:58,
46remote: from ../src/binding.cpp:1:
47remote: ../src/binding.cpp: At global scope:
48remote: /app/.node-gyp/16.13.1/include/node/node.h:821:43: warning: cast between incompatible function types from ‘void (*)(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE)’ {aka ‘void (*)(v8::Local<v8::Object>)’} to ‘node::addon_register_func’ {aka ‘void (*)(v8::Local<v8::Object>, v8::Local<v8::Value>, void*)’} [-Wcast-function-type]
49remote: 821 | (node::addon_register_func) (regfunc), \
50remote: | ^
51remote: /app/.node-gyp/16.13.1/include/node/node.h:855:3: note: in expansion of macro ‘NODE_MODULE_X’
52remote: 855 | NODE_MODULE_X(modname, regfunc, NULL, 0) // NOLINT (readability/null_usage)
53remote: | ^~~~~~~~~~~~~
54remote: ../src/binding.cpp:358:1: note: in expansion of macro ‘NODE_MODULE’
55remote: 358 | NODE_MODULE(binding, RegisterModule);
56remote: | ^~~~~~~~~~~
57remote: make: *** [binding.target.mk:133: Release/obj.target/binding/src/binding.o] Error 1
58remote: make: Leaving directory '/tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-sass/build'
59remote: gyp ERR! build error
60remote: gyp ERR! stack Error: `make` failed with exit code: 2
61remote: gyp ERR! stack at ChildProcess.onExit (/tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-gyp/lib/build.js:262:23)
62remote: gyp ERR! stack at ChildProcess.emit (node:events:390:28)
63remote: gyp ERR! stack at Process.ChildProcess._handle.onexit (node:internal/child_process:290:12)
64remote: gyp ERR! System Linux 4.4.0-1097-aws
65remote: gyp ERR! command "/tmp/build_df192222/bin/node" "/tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-gyp/bin/node-gyp.js" "rebuild" "--verbose" "--libsass_ext=" "--libsass_cflags=" "--libsass_ldflags=" "--libsass_library="
66remote: gyp ERR! cwd /tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-sass
67remote: gyp ERR! node -v v16.13.1
68remote: gyp ERR! node-gyp -v v3.8.0
69remote: gyp ERR! not ok
70remote: Build failed with error code: 1
71remote:
72remote: !
73remote: ! Precompiling assets failed.
74remote: !
75remote: ! Push rejected, failed to compile Ruby app.
76remote:
77remote: ! Push failed
78
Though it is a Rails app I added node in engines to package.json.
1yarn install v1.22.17
2remote: warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json.
3remote: [1/5] Validating package.json...
4remote: [2/5] Resolving packages...
5remote: [3/5] Fetching packages...
6remote: [4/5] Linking dependencies...
7remote: warning " > webpack-dev-server@4.6.0" has unmet peer dependency "webpack@^4.37.0 || ^5.0.0".
8remote: warning "webpack-dev-server > webpack-dev-middleware@5.2.1" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
9remote: [5/5] Building fresh packages...
10remote: error /tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-sass: Command failed.
11remote: Exit code: 1
12remote: Command: node scripts/build.js
13remote: Arguments:
14remote: Directory: /tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-sass
15remote: Output:
16remote: Building: /tmp/build_df192222/bin/node /tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-gyp/bin/node-gyp.js rebuild --verbose --libsass_ext= --libsass_cflags= --libsass_ldflags= --libsass_library=
17remote: gyp info it worked if it ends with ok
18remote: gyp verb cli [
19remote: gyp verb cli '/tmp/build_df192222/bin/node',
20remote: gyp verb cli '/tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-gyp/bin/node-gyp.js',
21remote: gyp verb cli 'rebuild',
22remote: /app/.node-gyp/16.13.1/include/node/v8-internal.h: In function ‘void v8::internal::PerformCastCheck(T*)’:
23remote: /app/.node-gyp/16.13.1/include/node/v8-internal.h:492:38: error: ‘remove_cv_t’ is not a member of ‘std’; did you mean ‘remove_cv’?
24remote: 492 | !std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data);
25remote: | ^~~~~~~~~~~
26remote: | remove_cv
27remote: /app/.node-gyp/16.13.1/include/node/v8-internal.h:492:38: error: ‘remove_cv_t’ is not a member of ‘std’; did you mean ‘remove_cv’?
28remote: 492 | !std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data);
29remote: | ^~~~~~~~~~~
30remote: | remove_cv
31remote: /app/.node-gyp/16.13.1/include/node/v8-internal.h:492:50: error: template argument 2 is invalid
32remote: 492 | !std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data);
33remote: | ^
34remote: /app/.node-gyp/16.13.1/include/node/v8-internal.h:492:63: error: ‘::Perform’ has not been declared
35remote: 492 | !std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data);
36remote: | ^~~~~~~
37remote: ../src/binding.cpp: In function ‘Nan::NAN_METHOD_RETURN_TYPE render(Nan::NAN_METHOD_ARGS_TYPE)’:
38remote: ../src/binding.cpp:284:98: warning: cast between incompatible function types from ‘void (*)(uv_work_t*)’ {aka ‘void (*)(uv_work_s*)’} to ‘uv_after_work_cb’ {aka ‘void (*)(uv_work_s*, int)’} [-Wcast-function-type]
39remote: 284 | int status = uv_queue_work(uv_default_loop(), &ctx_w->request, compile_it, (uv_after_work_cb)MakeCallback);
40remote: | ^~~~~~~~~~~~
41remote: ../src/binding.cpp: In function ‘Nan::NAN_METHOD_RETURN_TYPE render_file(Nan::NAN_METHOD_ARGS_TYPE)’:
42remote: ../src/binding.cpp:320:98: warning: cast between incompatible function types from ‘void (*)(uv_work_t*)’ {aka ‘void (*)(uv_work_s*)’} to ‘uv_after_work_cb’ {aka ‘void (*)(uv_work_s*, int)’} [-Wcast-function-type]
43remote: 320 | int status = uv_queue_work(uv_default_loop(), &ctx_w->request, compile_it, (uv_after_work_cb)MakeCallback);
44remote: | ^~~~~~~~~~~~
45remote: In file included from ../../../../../nan/nan.h:58,
46remote: from ../src/binding.cpp:1:
47remote: ../src/binding.cpp: At global scope:
48remote: /app/.node-gyp/16.13.1/include/node/node.h:821:43: warning: cast between incompatible function types from ‘void (*)(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE)’ {aka ‘void (*)(v8::Local<v8::Object>)’} to ‘node::addon_register_func’ {aka ‘void (*)(v8::Local<v8::Object>, v8::Local<v8::Value>, void*)’} [-Wcast-function-type]
49remote: 821 | (node::addon_register_func) (regfunc), \
50remote: | ^
51remote: /app/.node-gyp/16.13.1/include/node/node.h:855:3: note: in expansion of macro ‘NODE_MODULE_X’
52remote: 855 | NODE_MODULE_X(modname, regfunc, NULL, 0) // NOLINT (readability/null_usage)
53remote: | ^~~~~~~~~~~~~
54remote: ../src/binding.cpp:358:1: note: in expansion of macro ‘NODE_MODULE’
55remote: 358 | NODE_MODULE(binding, RegisterModule);
56remote: | ^~~~~~~~~~~
57remote: make: *** [binding.target.mk:133: Release/obj.target/binding/src/binding.o] Error 1
58remote: make: Leaving directory '/tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-sass/build'
59remote: gyp ERR! build error
60remote: gyp ERR! stack Error: `make` failed with exit code: 2
61remote: gyp ERR! stack at ChildProcess.onExit (/tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-gyp/lib/build.js:262:23)
62remote: gyp ERR! stack at ChildProcess.emit (node:events:390:28)
63remote: gyp ERR! stack at Process.ChildProcess._handle.onexit (node:internal/child_process:290:12)
64remote: gyp ERR! System Linux 4.4.0-1097-aws
65remote: gyp ERR! command "/tmp/build_df192222/bin/node" "/tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-gyp/bin/node-gyp.js" "rebuild" "--verbose" "--libsass_ext=" "--libsass_cflags=" "--libsass_ldflags=" "--libsass_library="
66remote: gyp ERR! cwd /tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-sass
67remote: gyp ERR! node -v v16.13.1
68remote: gyp ERR! node-gyp -v v3.8.0
69remote: gyp ERR! not ok
70remote: Build failed with error code: 1
71remote:
72remote: !
73remote: ! Precompiling assets failed.
74remote: !
75remote: ! Push rejected, failed to compile Ruby app.
76remote:
77remote: ! Push failed
78{
79 "name": "travel_empire",
80 "private": true,
81 "dependencies": {
82 "@fortawesome/fontawesome-free": "^5.15.4",
83 "@popperjs/core": "^2.10.2",
84 "@rails/actioncable": "^6.0.0",
85 "@rails/activestorage": "^6.0.0",
86 "@rails/ujs": "^6.0.0",
87 "@rails/webpacker": "4.3.0",
88 "bootstrap": "4.3.1",
89 "bootstrap-icons": "^1.5.0",
90 "easy-autocomplete": "^1.3.5",
91 "jquery": "^3.6.0",
92 "jquery-ui-dist": "^1.12.1",
93 "js-autocomplete": "^1.0.4",
94 "node-sass": "^7.0.0",
95 "popper.js": "^1.16.1",
96 "turbolinks": "^5.2.0"
97 },
98 "version": "0.1.0",
99 "devDependencies": {
100 "webpack-dev-server": "^4.6.0"
101 },
102 "engines": {
103 "node": "16.x"
104 }
105}
106
Gemfile
1yarn install v1.22.17
2remote: warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json.
3remote: [1/5] Validating package.json...
4remote: [2/5] Resolving packages...
5remote: [3/5] Fetching packages...
6remote: [4/5] Linking dependencies...
7remote: warning " > webpack-dev-server@4.6.0" has unmet peer dependency "webpack@^4.37.0 || ^5.0.0".
8remote: warning "webpack-dev-server > webpack-dev-middleware@5.2.1" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
9remote: [5/5] Building fresh packages...
10remote: error /tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-sass: Command failed.
11remote: Exit code: 1
12remote: Command: node scripts/build.js
13remote: Arguments:
14remote: Directory: /tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-sass
15remote: Output:
16remote: Building: /tmp/build_df192222/bin/node /tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-gyp/bin/node-gyp.js rebuild --verbose --libsass_ext= --libsass_cflags= --libsass_ldflags= --libsass_library=
17remote: gyp info it worked if it ends with ok
18remote: gyp verb cli [
19remote: gyp verb cli '/tmp/build_df192222/bin/node',
20remote: gyp verb cli '/tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-gyp/bin/node-gyp.js',
21remote: gyp verb cli 'rebuild',
22remote: /app/.node-gyp/16.13.1/include/node/v8-internal.h: In function ‘void v8::internal::PerformCastCheck(T*)’:
23remote: /app/.node-gyp/16.13.1/include/node/v8-internal.h:492:38: error: ‘remove_cv_t’ is not a member of ‘std’; did you mean ‘remove_cv’?
24remote: 492 | !std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data);
25remote: | ^~~~~~~~~~~
26remote: | remove_cv
27remote: /app/.node-gyp/16.13.1/include/node/v8-internal.h:492:38: error: ‘remove_cv_t’ is not a member of ‘std’; did you mean ‘remove_cv’?
28remote: 492 | !std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data);
29remote: | ^~~~~~~~~~~
30remote: | remove_cv
31remote: /app/.node-gyp/16.13.1/include/node/v8-internal.h:492:50: error: template argument 2 is invalid
32remote: 492 | !std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data);
33remote: | ^
34remote: /app/.node-gyp/16.13.1/include/node/v8-internal.h:492:63: error: ‘::Perform’ has not been declared
35remote: 492 | !std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data);
36remote: | ^~~~~~~
37remote: ../src/binding.cpp: In function ‘Nan::NAN_METHOD_RETURN_TYPE render(Nan::NAN_METHOD_ARGS_TYPE)’:
38remote: ../src/binding.cpp:284:98: warning: cast between incompatible function types from ‘void (*)(uv_work_t*)’ {aka ‘void (*)(uv_work_s*)’} to ‘uv_after_work_cb’ {aka ‘void (*)(uv_work_s*, int)’} [-Wcast-function-type]
39remote: 284 | int status = uv_queue_work(uv_default_loop(), &ctx_w->request, compile_it, (uv_after_work_cb)MakeCallback);
40remote: | ^~~~~~~~~~~~
41remote: ../src/binding.cpp: In function ‘Nan::NAN_METHOD_RETURN_TYPE render_file(Nan::NAN_METHOD_ARGS_TYPE)’:
42remote: ../src/binding.cpp:320:98: warning: cast between incompatible function types from ‘void (*)(uv_work_t*)’ {aka ‘void (*)(uv_work_s*)’} to ‘uv_after_work_cb’ {aka ‘void (*)(uv_work_s*, int)’} [-Wcast-function-type]
43remote: 320 | int status = uv_queue_work(uv_default_loop(), &ctx_w->request, compile_it, (uv_after_work_cb)MakeCallback);
44remote: | ^~~~~~~~~~~~
45remote: In file included from ../../../../../nan/nan.h:58,
46remote: from ../src/binding.cpp:1:
47remote: ../src/binding.cpp: At global scope:
48remote: /app/.node-gyp/16.13.1/include/node/node.h:821:43: warning: cast between incompatible function types from ‘void (*)(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE)’ {aka ‘void (*)(v8::Local<v8::Object>)’} to ‘node::addon_register_func’ {aka ‘void (*)(v8::Local<v8::Object>, v8::Local<v8::Value>, void*)’} [-Wcast-function-type]
49remote: 821 | (node::addon_register_func) (regfunc), \
50remote: | ^
51remote: /app/.node-gyp/16.13.1/include/node/node.h:855:3: note: in expansion of macro ‘NODE_MODULE_X’
52remote: 855 | NODE_MODULE_X(modname, regfunc, NULL, 0) // NOLINT (readability/null_usage)
53remote: | ^~~~~~~~~~~~~
54remote: ../src/binding.cpp:358:1: note: in expansion of macro ‘NODE_MODULE’
55remote: 358 | NODE_MODULE(binding, RegisterModule);
56remote: | ^~~~~~~~~~~
57remote: make: *** [binding.target.mk:133: Release/obj.target/binding/src/binding.o] Error 1
58remote: make: Leaving directory '/tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-sass/build'
59remote: gyp ERR! build error
60remote: gyp ERR! stack Error: `make` failed with exit code: 2
61remote: gyp ERR! stack at ChildProcess.onExit (/tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-gyp/lib/build.js:262:23)
62remote: gyp ERR! stack at ChildProcess.emit (node:events:390:28)
63remote: gyp ERR! stack at Process.ChildProcess._handle.onexit (node:internal/child_process:290:12)
64remote: gyp ERR! System Linux 4.4.0-1097-aws
65remote: gyp ERR! command "/tmp/build_df192222/bin/node" "/tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-gyp/bin/node-gyp.js" "rebuild" "--verbose" "--libsass_ext=" "--libsass_cflags=" "--libsass_ldflags=" "--libsass_library="
66remote: gyp ERR! cwd /tmp/build_df192222/node_modules/@rails/webpacker/node_modules/node-sass
67remote: gyp ERR! node -v v16.13.1
68remote: gyp ERR! node-gyp -v v3.8.0
69remote: gyp ERR! not ok
70remote: Build failed with error code: 1
71remote:
72remote: !
73remote: ! Precompiling assets failed.
74remote: !
75remote: ! Push rejected, failed to compile Ruby app.
76remote:
77remote: ! Push failed
78{
79 "name": "travel_empire",
80 "private": true,
81 "dependencies": {
82 "@fortawesome/fontawesome-free": "^5.15.4",
83 "@popperjs/core": "^2.10.2",
84 "@rails/actioncable": "^6.0.0",
85 "@rails/activestorage": "^6.0.0",
86 "@rails/ujs": "^6.0.0",
87 "@rails/webpacker": "4.3.0",
88 "bootstrap": "4.3.1",
89 "bootstrap-icons": "^1.5.0",
90 "easy-autocomplete": "^1.3.5",
91 "jquery": "^3.6.0",
92 "jquery-ui-dist": "^1.12.1",
93 "js-autocomplete": "^1.0.4",
94 "node-sass": "^7.0.0",
95 "popper.js": "^1.16.1",
96 "turbolinks": "^5.2.0"
97 },
98 "version": "0.1.0",
99 "devDependencies": {
100 "webpack-dev-server": "^4.6.0"
101 },
102 "engines": {
103 "node": "16.x"
104 }
105}
106source 'https://rubygems.org'
107git_source(:github) { |repo| "https://github.com/#{repo}.git" }
108
109ruby '2.7.3'
110
111# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
112gem 'rails', '~> 6.0.3', '>= 6.0.3.7'
113
114gem 'mongoid', git: 'https://github.com/mongodb/mongoid.git'
115
116
117# Use Puma as the app server
118gem 'puma', '~> 4.1'
119# Use SCSS for stylesheets
120gem 'sass-rails', '>= 6'
121# Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker
122gem 'webpacker', '~> 4.0'
123# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
124gem 'turbolinks', '~> 5'
125# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
126gem 'jbuilder', '~> 2.7'
127# Use Redis adapter to run Action Cable in production
128# gem 'redis', '~> 4.0'
129# Use Active Model has_secure_password
130
131
132# Use Active Storage variant
133# gem 'image_processing', '~> 1.2'
134
135
136gem 'axlsx'
137gem 'caxlsx_rails'
138
139
140#Bootstrap for UI
141gem 'bootstrap', '~> 5.1.0'
142gem 'bootstrap-timepicker-rails', '~> 0.1.3'
143gem 'bootstrap-select-rails', '~> 1.6', '>= 1.6.3'
144#JQuery Rails
145gem 'jquery-rails'
146
147 gem 'rails_12factor', group: :production
148# Reduces boot times through caching; required in config/boot.rb
149gem 'bootsnap', '>= 1.4.2', require: false
150
151group :development, :test do
152 # Call 'byebug' anywhere in the code to stop execution and get a debugger console
153 gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
154end
155
156group :development do
157 # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
158 gem 'web-console', '>= 3.3.0'
159 gem 'listen', '~> 3.2'
160 gem 'pry'
161 # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
162 gem 'spring'
163 gem 'spring-watcher-listen', '~> 2.0.0'
164end
165
166group :test do
167 # Adds support for Capybara system testing and selenium driver
168 gem 'capybara', '>= 2.15'
169 gem 'selenium-webdriver'
170 # Easy installation and use of web drivers to run system tests with browsers
171 gem 'webdrivers'
172 gem 'cucumber-rails', require: false
173 gem 'database_cleaner'
174end
175
176# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
177gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
178
179#HTTParty for RESTful API calls
180gem 'httparty'
181
182
183#Paperclip for storing files
184gem 'paperclip'
185gem "mongoid-paperclip", :require => "mongoid_paperclip"
186
187gem "letter_opener", :group => :development
188
ANSWER
Answered 2021-Dec-18 at 14:32I had a similar problem but resolved by following steps.
- Run the following command.
heroku buildpacks:add heroku/nodejs --index 1
- Update node version from
16.x
to12.16.2
in package.json.
QUESTION
Getting keyboard navigation to work with MUI Autocomplete and SimpleBar for react
Asked 2021-Dec-30 at 20:06I am trying to add Simplebar scrollbar to the MUI Material Autocomplete component, instead of the default browser one. All works but doing that I've lost the ability to navigate the options list with the keyboard.
There is this snippet from the MUI docs
ListboxComponent If you provide a custom ListboxComponent prop, you need to make sure that the intended scroll container has the role attribute set to listbox. This ensures the correct behavior of the scroll, for example when using the keyboard to navigate.
But I have no idea how to do that.
The following code is from the MUI docs, first autocomplete example with custom ListboxComponenet and shortened movie list. (https://mui.com/components/autocomplete/)
1import * as React from 'react';
2import TextField from '@mui/material/TextField';
3import Autocomplete from '@mui/material/Autocomplete';
4
5import SimpleBar from "simplebar-react";
6import "simplebar/dist/simplebar.min.css";
7
8export default function ComboBox() {
9 return (
10 <Autocomplete
11 disablePortal
12 id="combo-box-demo"
13 options={top100Films}
14 ListboxComponent={SimpleBar}
15 sx={{ width: 300 }}
16 renderInput={(params) => <TextField {...params} label="Movie" />}
17 />
18 );
19}
20
21// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
22const top100Films = [
23 { label: 'City of God', year: 2002 },
24 { label: 'Se7en', year: 1995 },
25 { label: 'The Silence of the Lambs', year: 1991 },
26 { label: "It's a Wonderful Life", year: 1946 },
27 { label: 'Life Is Beautiful', year: 1997 },
28 { label: 'The Usual Suspects', year: 1995 },
29 { label: 'Léon: The Professional', year: 1994 },
30 { label: 'Spirited Away', year: 2001 },
31 { label: 'Saving Private Ryan', year: 1998 },
32 { label: 'Once Upon a Time in the West', year: 1968 },
33 { label: 'American History X', year: 1998 },
34 { label: 'Interstellar', year: 2014 },
35 { label: 'Casablanca', year: 1942 },
36 { label: 'City Lights', year: 1931 },
37 { label: 'Psycho', year: 1960 },
38 { label: 'The Green Mile', year: 1999 },
39 { label: 'The Intouchables', year: 2011 },
40 { label: 'Modern Times', year: 1936 },
41 { label: 'Raiders of the Lost Ark', year: 1981 },
42 { label: 'Rear Window', year: 1954 },
43 { label: 'The Pianist', year: 2002 },
44 { label: 'The Departed', year: 2006 },
45 { label: 'Terminator 2: Judgment Day', year: 1991 },
46 { label: 'Back to the Future', year: 1985 },
47 { label: 'Whiplash', year: 2014 },
48 { label: 'Gladiator', year: 2000 },
49 { label: 'Memento', year: 2000 },
50];
51
I have also tried the following but that also doesn't seem to work.
1import * as React from 'react';
2import TextField from '@mui/material/TextField';
3import Autocomplete from '@mui/material/Autocomplete';
4
5import SimpleBar from "simplebar-react";
6import "simplebar/dist/simplebar.min.css";
7
8export default function ComboBox() {
9 return (
10 <Autocomplete
11 disablePortal
12 id="combo-box-demo"
13 options={top100Films}
14 ListboxComponent={SimpleBar}
15 sx={{ width: 300 }}
16 renderInput={(params) => <TextField {...params} label="Movie" />}
17 />
18 );
19}
20
21// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
22const top100Films = [
23 { label: 'City of God', year: 2002 },
24 { label: 'Se7en', year: 1995 },
25 { label: 'The Silence of the Lambs', year: 1991 },
26 { label: "It's a Wonderful Life", year: 1946 },
27 { label: 'Life Is Beautiful', year: 1997 },
28 { label: 'The Usual Suspects', year: 1995 },
29 { label: 'Léon: The Professional', year: 1994 },
30 { label: 'Spirited Away', year: 2001 },
31 { label: 'Saving Private Ryan', year: 1998 },
32 { label: 'Once Upon a Time in the West', year: 1968 },
33 { label: 'American History X', year: 1998 },
34 { label: 'Interstellar', year: 2014 },
35 { label: 'Casablanca', year: 1942 },
36 { label: 'City Lights', year: 1931 },
37 { label: 'Psycho', year: 1960 },
38 { label: 'The Green Mile', year: 1999 },
39 { label: 'The Intouchables', year: 2011 },
40 { label: 'Modern Times', year: 1936 },
41 { label: 'Raiders of the Lost Ark', year: 1981 },
42 { label: 'Rear Window', year: 1954 },
43 { label: 'The Pianist', year: 2002 },
44 { label: 'The Departed', year: 2006 },
45 { label: 'Terminator 2: Judgment Day', year: 1991 },
46 { label: 'Back to the Future', year: 1985 },
47 { label: 'Whiplash', year: 2014 },
48 { label: 'Gladiator', year: 2000 },
49 { label: 'Memento', year: 2000 },
50];
51ListboxComponent={(props) => <SimpleBar {...props} role="listbox" />}
52
Any help would be appreciated, thanks.
ANSWER
Answered 2021-Dec-30 at 20:06The problem is actually very complicated. Looking at its implementation, <SimpleBar />
doesn't pass either the React ref
or the role
prop to the correct element. The correct element I believe is .scrollbar-content
, which is very deeply nested and basically untouchable.
ETA: In case you thought of getting cheesy with document.querySelectorAll
setAttribute
shenanigans, that will not work. The ref
also needs to point at the correct element, and I don't think that's codeable on the workspace side.
The cleanest solution I can think of is to use Yarn 3 (👍) and patch simplebar-react
yourself, passing the needed props to .scrollbar-content
. Then you do:
1import * as React from 'react';
2import TextField from '@mui/material/TextField';
3import Autocomplete from '@mui/material/Autocomplete';
4
5import SimpleBar from "simplebar-react";
6import "simplebar/dist/simplebar.min.css";
7
8export default function ComboBox() {
9 return (
10 <Autocomplete
11 disablePortal
12 id="combo-box-demo"
13 options={top100Films}
14 ListboxComponent={SimpleBar}
15 sx={{ width: 300 }}
16 renderInput={(params) => <TextField {...params} label="Movie" />}
17 />
18 );
19}
20
21// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
22const top100Films = [
23 { label: 'City of God', year: 2002 },
24 { label: 'Se7en', year: 1995 },
25 { label: 'The Silence of the Lambs', year: 1991 },
26 { label: "It's a Wonderful Life", year: 1946 },
27 { label: 'Life Is Beautiful', year: 1997 },
28 { label: 'The Usual Suspects', year: 1995 },
29 { label: 'Léon: The Professional', year: 1994 },
30 { label: 'Spirited Away', year: 2001 },
31 { label: 'Saving Private Ryan', year: 1998 },
32 { label: 'Once Upon a Time in the West', year: 1968 },
33 { label: 'American History X', year: 1998 },
34 { label: 'Interstellar', year: 2014 },
35 { label: 'Casablanca', year: 1942 },
36 { label: 'City Lights', year: 1931 },
37 { label: 'Psycho', year: 1960 },
38 { label: 'The Green Mile', year: 1999 },
39 { label: 'The Intouchables', year: 2011 },
40 { label: 'Modern Times', year: 1936 },
41 { label: 'Raiders of the Lost Ark', year: 1981 },
42 { label: 'Rear Window', year: 1954 },
43 { label: 'The Pianist', year: 2002 },
44 { label: 'The Departed', year: 2006 },
45 { label: 'Terminator 2: Judgment Day', year: 1991 },
46 { label: 'Back to the Future', year: 1985 },
47 { label: 'Whiplash', year: 2014 },
48 { label: 'Gladiator', year: 2000 },
49 { label: 'Memento', year: 2000 },
50];
51ListboxComponent={(props) => <SimpleBar {...props} role="listbox" />}
52const ListboxSimpleBar = React.forwardRef(function ListboxSimpleBar(props, ref) {
53 return <SimpleBar {...props} role='listbox' listboxRef={ref} />
54}
55
56// ...
57ListboxComponent={ListboxSimpleBar}
58
The less clean solution is to fork the repo, patch it, and install it as a git dependency. Or publish to npm once you're sure it works and install as a regular dependency. That's the recommended method if you don't use Yarn 3 (👎). It's much more tedious and won't receive updates, but it is an option that exists.
The least clean solution is to copypasterino the simplebar-react code in your own workspace, edit it and import it in lieu of the real simplebar-react. Hackier, messier and funnier option 2, but only just barely.
QUESTION
Disable irb autocomplete
Asked 2021-Dec-28 at 16:24The latest version of irb introduced an autocomplete that is quite buggy and I don't generally like to be distracted by an autocomplete, any idea how I can disable it?
ANSWER
Answered 2021-Dec-28 at 16:24Try putting this in your ~/.irbrc
1IRB.conf[:USE_AUTOCOMPLETE] = false
2
QUESTION
Why typescript does not properly infer T[K] with <T extends Person, K extends keyof T> generic?
Asked 2021-Dec-18 at 21:55I have created a React hook:
1interface Person {
2 name: string
3 age: number
4}
5
6export const usePerson = function <T extends Person, K extends keyof T>(): (property: K, setter: (value: T[K]) => T[K]) => void {
7
8 const setPersonProperty = (property: K, setter: (value: T[K]) => T[K]): void => {
9 console.log(property, setter)
10 }
11
12 setPersonProperty('name', (x) => x)
13
14 return setPersonProperty;
15}
16
I have seen the pattern <T, K extends keyof T>
from typescript docs but I am unable to use it correctly in my example.
More specifically, the typescript complains on the line
1interface Person {
2 name: string
3 age: number
4}
5
6export const usePerson = function <T extends Person, K extends keyof T>(): (property: K, setter: (value: T[K]) => T[K]) => void {
7
8 const setPersonProperty = (property: K, setter: (value: T[K]) => T[K]): void => {
9 console.log(property, setter)
10 }
11
12 setPersonProperty('name', (x) => x)
13
14 return setPersonProperty;
15}
16setPersonProperty('name', (x) => x)
17
Although when I start typing setPersonProperty('n /* IDE autocompletes name */
but complains for the 'name'
parameter and I get the following error:
1interface Person {
2 name: string
3 age: number
4}
5
6export const usePerson = function <T extends Person, K extends keyof T>(): (property: K, setter: (value: T[K]) => T[K]) => void {
7
8 const setPersonProperty = (property: K, setter: (value: T[K]) => T[K]): void => {
9 console.log(property, setter)
10 }
11
12 setPersonProperty('name', (x) => x)
13
14 return setPersonProperty;
15}
16setPersonProperty('name', (x) => x)
17Argument of type 'string' is not assignable to parameter of type 'K'. 'string' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string | number | symbol'.
18
I have also posted an image from my IDE. I am using typescript 4+. [![enter image description here][1]][1]
What am I doing wrong here ? [1]: https://i.stack.imgur.com/WzJE5.png
ANSWER
Answered 2021-Dec-18 at 21:55I bet that this is the result You want to achieve
1interface Person {
2 name: string
3 age: number
4}
5
6export const usePerson = function <T extends Person, K extends keyof T>(): (property: K, setter: (value: T[K]) => T[K]) => void {
7
8 const setPersonProperty = (property: K, setter: (value: T[K]) => T[K]): void => {
9 console.log(property, setter)
10 }
11
12 setPersonProperty('name', (x) => x)
13
14 return setPersonProperty;
15}
16setPersonProperty('name', (x) => x)
17Argument of type 'string' is not assignable to parameter of type 'K'. 'string' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string | number | symbol'.
18type Person = {
19 name: string,
20 age: number
21};
22
23export const usePerson = function <T extends Person>() {
24 const setPersonProperty = <K extends keyof T> (property: K, setter: (value: T[K]) => T[K]): void => {
25 console.log(property, setter)
26 }
27
28 setPersonProperty("name", (x) => x)
29
30 return setPersonProperty;
31}
32
33 const setPerson = usePerson<Person>()
34
35 setPerson("name", (name) => name)
36
37
Basically, in code you provided there are two generic types when calling this usePerson hook T
and K
(<T extends Person, K extends keyof T>
).
Let's say someone will call this function with usePerson<Person, "age">()
.
What typescript will do it will replace types inside our usePerson
to be T = Person
and K = "age"
And now you have a mismatch since setPersonProperty
have first argument of type K ("age") the argument "name" is not assignable - that the error you see.
QUESTION
Typescript: deep keyof of a nested object, with related type
Asked 2021-Dec-02 at 09:30I'm looking for a way to have all keys / values pair of a nested object.
(For the autocomplete of MongoDB dot notation key / value type)
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9
Here is what I want to achieve, to make it becomes:
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16
In this answer, I can get the key with Leaves<IPerson>
.
So it becomes 'name' | 'age' | 'contact.address' | 'contact.visitDate'
.
And in another answer from @jcalz, I can get the deep, related value type, with DeepIndex<IPerson, ...>
.
Is it possible to group them together, to become type like TPerson
?
When I start this question, I was thinking it could be as easy as something like [K in keyof T]: T[K];
, with some clever transformation. But I was wrong. Here is what I need:
So the interface
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22
becomes
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30
No need to check for valid number
, the nature of Array / Index Signature should allow any number of elements.
The interface
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33
becomes
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38
Tuple should be the one which cares about valid index numbers.
3. Readonlyreadonly
attributes should be removed from the final structure.
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43
becomes
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46
The use case is for MongoDB, the _id
, _created_date
cannot be modified after the data has been created. _id: never
is not working in this case, since it will block the creation of TPerson
.
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52
becomes
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60
It's sufficient just to bring the optional flags to transformed structure.
5. Intersection1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63
becomes
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63type TPerson = {
64 [x: `contact.address`]: string;
65 [x: `contact.visitDate`]?: Date;
66 contact: { address: string; } & { visitDate: Date; }
67}
68
The interface
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63type TPerson = {
64 [x: `contact.address`]: string;
65 [x: `contact.visitDate`]?: Date;
66 contact: { address: string; } & { visitDate: Date; }
67}
68interface IPerson {
69 birth: Date;
70}
71
becomes
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63type TPerson = {
64 [x: `contact.address`]: string;
65 [x: `contact.visitDate`]?: Date;
66 contact: { address: string; } & { visitDate: Date; }
67}
68interface IPerson {
69 birth: Date;
70}
71type TPerson = {
72 birth: Date;
73}
74
not
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63type TPerson = {
64 [x: `contact.address`]: string;
65 [x: `contact.visitDate`]?: Date;
66 contact: { address: string; } & { visitDate: Date; }
67}
68interface IPerson {
69 birth: Date;
70}
71type TPerson = {
72 birth: Date;
73}
74type TPerson = {
75 age: Date;
76 "age.toDateString": () => string;
77 "age.toTimeString": () => string;
78 "age.toLocaleDateString": {
79 ...
80}
81
We can give a list of Types to be the end node.
Here is what I don't need:- Union. It could be too complex with it.
- Class related keyword. No need to handle keywords ex: private / abstract .
- All the rest I didn't write it here.
ANSWER
Answered 2021-Dec-02 at 09:30In order to achieve this goal we need to create permutation of all allowed paths. For example:
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63type TPerson = {
64 [x: `contact.address`]: string;
65 [x: `contact.visitDate`]?: Date;
66 contact: { address: string; } & { visitDate: Date; }
67}
68interface IPerson {
69 birth: Date;
70}
71type TPerson = {
72 birth: Date;
73}
74type TPerson = {
75 age: Date;
76 "age.toDateString": () => string;
77 "age.toTimeString": () => string;
78 "age.toLocaleDateString": {
79 ...
80}
81type Structure = {
82 user: {
83 name: string,
84 surname: string
85 }
86}
87
88type BlackMagic<T>= T
89
90// user.name | user.surname
91type Result=BlackMagic<Structure>
92
Problem becomes more interesting with arrays and empty tuples.
Tuple, the array with explicit length, should be managed in this way:
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63type TPerson = {
64 [x: `contact.address`]: string;
65 [x: `contact.visitDate`]?: Date;
66 contact: { address: string; } & { visitDate: Date; }
67}
68interface IPerson {
69 birth: Date;
70}
71type TPerson = {
72 birth: Date;
73}
74type TPerson = {
75 age: Date;
76 "age.toDateString": () => string;
77 "age.toTimeString": () => string;
78 "age.toLocaleDateString": {
79 ...
80}
81type Structure = {
82 user: {
83 name: string,
84 surname: string
85 }
86}
87
88type BlackMagic<T>= T
89
90// user.name | user.surname
91type Result=BlackMagic<Structure>
92type Structure = {
93 user: {
94 arr: [1, 2],
95 }
96}
97
98type BlackMagic<T> = T
99
100// "user.arr" | "user.arr.0" | "user.arr.1"
101type Result = BlackMagic<Structure>
102
Logic is straitforward. But how we can handle number[]
? There is no guarantee that index 1
exists.
I have decided to use user.arr.${number}
.
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63type TPerson = {
64 [x: `contact.address`]: string;
65 [x: `contact.visitDate`]?: Date;
66 contact: { address: string; } & { visitDate: Date; }
67}
68interface IPerson {
69 birth: Date;
70}
71type TPerson = {
72 birth: Date;
73}
74type TPerson = {
75 age: Date;
76 "age.toDateString": () => string;
77 "age.toTimeString": () => string;
78 "age.toLocaleDateString": {
79 ...
80}
81type Structure = {
82 user: {
83 name: string,
84 surname: string
85 }
86}
87
88type BlackMagic<T>= T
89
90// user.name | user.surname
91type Result=BlackMagic<Structure>
92type Structure = {
93 user: {
94 arr: [1, 2],
95 }
96}
97
98type BlackMagic<T> = T
99
100// "user.arr" | "user.arr.0" | "user.arr.1"
101type Result = BlackMagic<Structure>
102type Structure = {
103 user: {
104 arr: number[],
105 }
106}
107
108type BlackMagic<T> = T
109
110// "user.arr" | `user.arr.${number}`
111type Result = BlackMagic<Structure>
112
We still have 1 problem. Empty tuple. Array with zero elements - []
. Do we need to allow indexing at all? I don't know. I decided to use -1
.
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63type TPerson = {
64 [x: `contact.address`]: string;
65 [x: `contact.visitDate`]?: Date;
66 contact: { address: string; } & { visitDate: Date; }
67}
68interface IPerson {
69 birth: Date;
70}
71type TPerson = {
72 birth: Date;
73}
74type TPerson = {
75 age: Date;
76 "age.toDateString": () => string;
77 "age.toTimeString": () => string;
78 "age.toLocaleDateString": {
79 ...
80}
81type Structure = {
82 user: {
83 name: string,
84 surname: string
85 }
86}
87
88type BlackMagic<T>= T
89
90// user.name | user.surname
91type Result=BlackMagic<Structure>
92type Structure = {
93 user: {
94 arr: [1, 2],
95 }
96}
97
98type BlackMagic<T> = T
99
100// "user.arr" | "user.arr.0" | "user.arr.1"
101type Result = BlackMagic<Structure>
102type Structure = {
103 user: {
104 arr: number[],
105 }
106}
107
108type BlackMagic<T> = T
109
110// "user.arr" | `user.arr.${number}`
111type Result = BlackMagic<Structure>
112type Structure = {
113 user: {
114 arr: [],
115 }
116}
117
118type BlackMagic<T> = T
119
120// "user.arr" | "user.arr.-1"
121type Result = BlackMagic<Structure>
122
I think the most important thing here is some convention. We can also use stringified `"never". I think it is up to OP how to handle it.
Since we know how we need to handle different cases we can start our implementation. Before we continue, we need to define several helpers.
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63type TPerson = {
64 [x: `contact.address`]: string;
65 [x: `contact.visitDate`]?: Date;
66 contact: { address: string; } & { visitDate: Date; }
67}
68interface IPerson {
69 birth: Date;
70}
71type TPerson = {
72 birth: Date;
73}
74type TPerson = {
75 age: Date;
76 "age.toDateString": () => string;
77 "age.toTimeString": () => string;
78 "age.toLocaleDateString": {
79 ...
80}
81type Structure = {
82 user: {
83 name: string,
84 surname: string
85 }
86}
87
88type BlackMagic<T>= T
89
90// user.name | user.surname
91type Result=BlackMagic<Structure>
92type Structure = {
93 user: {
94 arr: [1, 2],
95 }
96}
97
98type BlackMagic<T> = T
99
100// "user.arr" | "user.arr.0" | "user.arr.1"
101type Result = BlackMagic<Structure>
102type Structure = {
103 user: {
104 arr: number[],
105 }
106}
107
108type BlackMagic<T> = T
109
110// "user.arr" | `user.arr.${number}`
111type Result = BlackMagic<Structure>
112type Structure = {
113 user: {
114 arr: [],
115 }
116}
117
118type BlackMagic<T> = T
119
120// "user.arr" | "user.arr.-1"
121type Result = BlackMagic<Structure>
122type Values<T> = T[keyof T]
123{
124 // 1 | "John"
125 type _ = Values<{ age: 1, name: 'John' }>
126}
127
128type IsNever<T> = [T] extends [never] ? true : false;
129{
130 type _ = IsNever<never> // true
131 type __ = IsNever<true> // false
132}
133
134type IsTuple<T> =
135 (T extends Array<any> ?
136 (T['length'] extends number
137 ? (number extends T['length']
138 ? false
139 : true)
140 : true)
141 : false)
142{
143 type _ = IsTuple<[1, 2]> // true
144 type __ = IsTuple<number[]> // false
145 type ___ = IsTuple<{ length: 2 }> // false
146}
147
148type IsEmptyTuple<T extends Array<any>> = T['length'] extends 0 ? true : false
149{
150 type _ = IsEmptyTuple<[]> // true
151 type __ = IsEmptyTuple<[1]> // false
152 type ___ = IsEmptyTuple<number[]> // false
153
154}
155
I think naming and tests are self explanatory. At least I want to believe :D
Now, when we have all set of our utils, we can define our main util:
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63type TPerson = {
64 [x: `contact.address`]: string;
65 [x: `contact.visitDate`]?: Date;
66 contact: { address: string; } & { visitDate: Date; }
67}
68interface IPerson {
69 birth: Date;
70}
71type TPerson = {
72 birth: Date;
73}
74type TPerson = {
75 age: Date;
76 "age.toDateString": () => string;
77 "age.toTimeString": () => string;
78 "age.toLocaleDateString": {
79 ...
80}
81type Structure = {
82 user: {
83 name: string,
84 surname: string
85 }
86}
87
88type BlackMagic<T>= T
89
90// user.name | user.surname
91type Result=BlackMagic<Structure>
92type Structure = {
93 user: {
94 arr: [1, 2],
95 }
96}
97
98type BlackMagic<T> = T
99
100// "user.arr" | "user.arr.0" | "user.arr.1"
101type Result = BlackMagic<Structure>
102type Structure = {
103 user: {
104 arr: number[],
105 }
106}
107
108type BlackMagic<T> = T
109
110// "user.arr" | `user.arr.${number}`
111type Result = BlackMagic<Structure>
112type Structure = {
113 user: {
114 arr: [],
115 }
116}
117
118type BlackMagic<T> = T
119
120// "user.arr" | "user.arr.-1"
121type Result = BlackMagic<Structure>
122type Values<T> = T[keyof T]
123{
124 // 1 | "John"
125 type _ = Values<{ age: 1, name: 'John' }>
126}
127
128type IsNever<T> = [T] extends [never] ? true : false;
129{
130 type _ = IsNever<never> // true
131 type __ = IsNever<true> // false
132}
133
134type IsTuple<T> =
135 (T extends Array<any> ?
136 (T['length'] extends number
137 ? (number extends T['length']
138 ? false
139 : true)
140 : true)
141 : false)
142{
143 type _ = IsTuple<[1, 2]> // true
144 type __ = IsTuple<number[]> // false
145 type ___ = IsTuple<{ length: 2 }> // false
146}
147
148type IsEmptyTuple<T extends Array<any>> = T['length'] extends 0 ? true : false
149{
150 type _ = IsEmptyTuple<[]> // true
151 type __ = IsEmptyTuple<[1]> // false
152 type ___ = IsEmptyTuple<number[]> // false
153
154}
155/**
156 * If Cache is empty return Prop without dot,
157 * to avoid ".user"
158 */
159type HandleDot<
160 Cache extends string,
161 Prop extends string | number
162 > =
163 Cache extends ''
164 ? `${Prop}`
165 : `${Cache}.${Prop}`
166
167/**
168 * Simple iteration through object properties
169 */
170type HandleObject<Obj, Cache extends string> = {
171 [Prop in keyof Obj]:
172 // concat previous Cacha and Prop
173 | HandleDot<Cache, Prop & string>
174 // with next Cache and Prop
175 | Path<Obj[Prop], HandleDot<Cache, Prop & string>>
176}[keyof Obj]
177
178type Path<Obj, Cache extends string = ''> =
179 // if Obj is primitive
180 (Obj extends PropertyKey
181 // return Cache
182 ? Cache
183 // if Obj is Array (can be array, tuple, empty tuple)
184 : (Obj extends Array<unknown>
185 // and is tuple
186 ? (IsTuple<Obj> extends true
187 // and tuple is empty
188 ? (IsEmptyTuple<Obj> extends true
189 // call recursively Path with `-1` as an allowed index
190 ? Path<PropertyKey, HandleDot<Cache, -1>>
191 // if tuple is not empty we can handle it as regular object
192 : HandleObject<Obj, Cache>)
193 // if Obj is regular array call Path with union of all elements
194 : Path<Obj[number], HandleDot<Cache, number>>)
195 // if Obj is neither Array nor Tuple nor Primitive - treat is as object
196 : HandleObject<Obj, Cache>)
197 )
198
199// "user" | "user.arr" | `user.arr.${number}`
200type Test = Extract<Path<Structure>, string>
201
There is small issue. We should not return highest level props, like user
. We need paths with at least one dot.
There are two ways:
- extract all props without dots
- provide extra generic parameter for indexing the level.
Two options are easy to implement.
Obtain all props with dot (.)
:
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63type TPerson = {
64 [x: `contact.address`]: string;
65 [x: `contact.visitDate`]?: Date;
66 contact: { address: string; } & { visitDate: Date; }
67}
68interface IPerson {
69 birth: Date;
70}
71type TPerson = {
72 birth: Date;
73}
74type TPerson = {
75 age: Date;
76 "age.toDateString": () => string;
77 "age.toTimeString": () => string;
78 "age.toLocaleDateString": {
79 ...
80}
81type Structure = {
82 user: {
83 name: string,
84 surname: string
85 }
86}
87
88type BlackMagic<T>= T
89
90// user.name | user.surname
91type Result=BlackMagic<Structure>
92type Structure = {
93 user: {
94 arr: [1, 2],
95 }
96}
97
98type BlackMagic<T> = T
99
100// "user.arr" | "user.arr.0" | "user.arr.1"
101type Result = BlackMagic<Structure>
102type Structure = {
103 user: {
104 arr: number[],
105 }
106}
107
108type BlackMagic<T> = T
109
110// "user.arr" | `user.arr.${number}`
111type Result = BlackMagic<Structure>
112type Structure = {
113 user: {
114 arr: [],
115 }
116}
117
118type BlackMagic<T> = T
119
120// "user.arr" | "user.arr.-1"
121type Result = BlackMagic<Structure>
122type Values<T> = T[keyof T]
123{
124 // 1 | "John"
125 type _ = Values<{ age: 1, name: 'John' }>
126}
127
128type IsNever<T> = [T] extends [never] ? true : false;
129{
130 type _ = IsNever<never> // true
131 type __ = IsNever<true> // false
132}
133
134type IsTuple<T> =
135 (T extends Array<any> ?
136 (T['length'] extends number
137 ? (number extends T['length']
138 ? false
139 : true)
140 : true)
141 : false)
142{
143 type _ = IsTuple<[1, 2]> // true
144 type __ = IsTuple<number[]> // false
145 type ___ = IsTuple<{ length: 2 }> // false
146}
147
148type IsEmptyTuple<T extends Array<any>> = T['length'] extends 0 ? true : false
149{
150 type _ = IsEmptyTuple<[]> // true
151 type __ = IsEmptyTuple<[1]> // false
152 type ___ = IsEmptyTuple<number[]> // false
153
154}
155/**
156 * If Cache is empty return Prop without dot,
157 * to avoid ".user"
158 */
159type HandleDot<
160 Cache extends string,
161 Prop extends string | number
162 > =
163 Cache extends ''
164 ? `${Prop}`
165 : `${Cache}.${Prop}`
166
167/**
168 * Simple iteration through object properties
169 */
170type HandleObject<Obj, Cache extends string> = {
171 [Prop in keyof Obj]:
172 // concat previous Cacha and Prop
173 | HandleDot<Cache, Prop & string>
174 // with next Cache and Prop
175 | Path<Obj[Prop], HandleDot<Cache, Prop & string>>
176}[keyof Obj]
177
178type Path<Obj, Cache extends string = ''> =
179 // if Obj is primitive
180 (Obj extends PropertyKey
181 // return Cache
182 ? Cache
183 // if Obj is Array (can be array, tuple, empty tuple)
184 : (Obj extends Array<unknown>
185 // and is tuple
186 ? (IsTuple<Obj> extends true
187 // and tuple is empty
188 ? (IsEmptyTuple<Obj> extends true
189 // call recursively Path with `-1` as an allowed index
190 ? Path<PropertyKey, HandleDot<Cache, -1>>
191 // if tuple is not empty we can handle it as regular object
192 : HandleObject<Obj, Cache>)
193 // if Obj is regular array call Path with union of all elements
194 : Path<Obj[number], HandleDot<Cache, number>>)
195 // if Obj is neither Array nor Tuple nor Primitive - treat is as object
196 : HandleObject<Obj, Cache>)
197 )
198
199// "user" | "user.arr" | `user.arr.${number}`
200type Test = Extract<Path<Structure>, string>
201type WithDot<T extends string> = T extends `${string}.${string}` ? T : never
202
While above util is readable and maintainable, second one is a bit harder. We need to provide extra generic parameter in both Path
and HandleObject
.
See this example taken from other question / article:
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63type TPerson = {
64 [x: `contact.address`]: string;
65 [x: `contact.visitDate`]?: Date;
66 contact: { address: string; } & { visitDate: Date; }
67}
68interface IPerson {
69 birth: Date;
70}
71type TPerson = {
72 birth: Date;
73}
74type TPerson = {
75 age: Date;
76 "age.toDateString": () => string;
77 "age.toTimeString": () => string;
78 "age.toLocaleDateString": {
79 ...
80}
81type Structure = {
82 user: {
83 name: string,
84 surname: string
85 }
86}
87
88type BlackMagic<T>= T
89
90// user.name | user.surname
91type Result=BlackMagic<Structure>
92type Structure = {
93 user: {
94 arr: [1, 2],
95 }
96}
97
98type BlackMagic<T> = T
99
100// "user.arr" | "user.arr.0" | "user.arr.1"
101type Result = BlackMagic<Structure>
102type Structure = {
103 user: {
104 arr: number[],
105 }
106}
107
108type BlackMagic<T> = T
109
110// "user.arr" | `user.arr.${number}`
111type Result = BlackMagic<Structure>
112type Structure = {
113 user: {
114 arr: [],
115 }
116}
117
118type BlackMagic<T> = T
119
120// "user.arr" | "user.arr.-1"
121type Result = BlackMagic<Structure>
122type Values<T> = T[keyof T]
123{
124 // 1 | "John"
125 type _ = Values<{ age: 1, name: 'John' }>
126}
127
128type IsNever<T> = [T] extends [never] ? true : false;
129{
130 type _ = IsNever<never> // true
131 type __ = IsNever<true> // false
132}
133
134type IsTuple<T> =
135 (T extends Array<any> ?
136 (T['length'] extends number
137 ? (number extends T['length']
138 ? false
139 : true)
140 : true)
141 : false)
142{
143 type _ = IsTuple<[1, 2]> // true
144 type __ = IsTuple<number[]> // false
145 type ___ = IsTuple<{ length: 2 }> // false
146}
147
148type IsEmptyTuple<T extends Array<any>> = T['length'] extends 0 ? true : false
149{
150 type _ = IsEmptyTuple<[]> // true
151 type __ = IsEmptyTuple<[1]> // false
152 type ___ = IsEmptyTuple<number[]> // false
153
154}
155/**
156 * If Cache is empty return Prop without dot,
157 * to avoid ".user"
158 */
159type HandleDot<
160 Cache extends string,
161 Prop extends string | number
162 > =
163 Cache extends ''
164 ? `${Prop}`
165 : `${Cache}.${Prop}`
166
167/**
168 * Simple iteration through object properties
169 */
170type HandleObject<Obj, Cache extends string> = {
171 [Prop in keyof Obj]:
172 // concat previous Cacha and Prop
173 | HandleDot<Cache, Prop & string>
174 // with next Cache and Prop
175 | Path<Obj[Prop], HandleDot<Cache, Prop & string>>
176}[keyof Obj]
177
178type Path<Obj, Cache extends string = ''> =
179 // if Obj is primitive
180 (Obj extends PropertyKey
181 // return Cache
182 ? Cache
183 // if Obj is Array (can be array, tuple, empty tuple)
184 : (Obj extends Array<unknown>
185 // and is tuple
186 ? (IsTuple<Obj> extends true
187 // and tuple is empty
188 ? (IsEmptyTuple<Obj> extends true
189 // call recursively Path with `-1` as an allowed index
190 ? Path<PropertyKey, HandleDot<Cache, -1>>
191 // if tuple is not empty we can handle it as regular object
192 : HandleObject<Obj, Cache>)
193 // if Obj is regular array call Path with union of all elements
194 : Path<Obj[number], HandleDot<Cache, number>>)
195 // if Obj is neither Array nor Tuple nor Primitive - treat is as object
196 : HandleObject<Obj, Cache>)
197 )
198
199// "user" | "user.arr" | `user.arr.${number}`
200type Test = Extract<Path<Structure>, string>
201type WithDot<T extends string> = T extends `${string}.${string}` ? T : never
202type KeysUnion<T, Cache extends string = '', Level extends any[] = []> =
203 T extends PropertyKey ? Cache : {
204 [P in keyof T]:
205 P extends string
206 ? Cache extends ''
207 ? KeysUnion<T[P], `${P}`, [...Level, 1]>
208 : Level['length'] extends 1 // if it is a higher level - proceed
209 ? KeysUnion<T[P], `${Cache}.${P}`, [...Level, 1]>
210 : Level['length'] extends 2 // stop on second level
211 ? Cache | KeysUnion<T[P], `${Cache}`, [...Level, 1]>
212 : never
213 : never
214 }[keyof T]
215
Honestly, I don't think it will be easy for any one to read this.
We need to implement one more thing. We need to obtain a value by computed path.
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63type TPerson = {
64 [x: `contact.address`]: string;
65 [x: `contact.visitDate`]?: Date;
66 contact: { address: string; } & { visitDate: Date; }
67}
68interface IPerson {
69 birth: Date;
70}
71type TPerson = {
72 birth: Date;
73}
74type TPerson = {
75 age: Date;
76 "age.toDateString": () => string;
77 "age.toTimeString": () => string;
78 "age.toLocaleDateString": {
79 ...
80}
81type Structure = {
82 user: {
83 name: string,
84 surname: string
85 }
86}
87
88type BlackMagic<T>= T
89
90// user.name | user.surname
91type Result=BlackMagic<Structure>
92type Structure = {
93 user: {
94 arr: [1, 2],
95 }
96}
97
98type BlackMagic<T> = T
99
100// "user.arr" | "user.arr.0" | "user.arr.1"
101type Result = BlackMagic<Structure>
102type Structure = {
103 user: {
104 arr: number[],
105 }
106}
107
108type BlackMagic<T> = T
109
110// "user.arr" | `user.arr.${number}`
111type Result = BlackMagic<Structure>
112type Structure = {
113 user: {
114 arr: [],
115 }
116}
117
118type BlackMagic<T> = T
119
120// "user.arr" | "user.arr.-1"
121type Result = BlackMagic<Structure>
122type Values<T> = T[keyof T]
123{
124 // 1 | "John"
125 type _ = Values<{ age: 1, name: 'John' }>
126}
127
128type IsNever<T> = [T] extends [never] ? true : false;
129{
130 type _ = IsNever<never> // true
131 type __ = IsNever<true> // false
132}
133
134type IsTuple<T> =
135 (T extends Array<any> ?
136 (T['length'] extends number
137 ? (number extends T['length']
138 ? false
139 : true)
140 : true)
141 : false)
142{
143 type _ = IsTuple<[1, 2]> // true
144 type __ = IsTuple<number[]> // false
145 type ___ = IsTuple<{ length: 2 }> // false
146}
147
148type IsEmptyTuple<T extends Array<any>> = T['length'] extends 0 ? true : false
149{
150 type _ = IsEmptyTuple<[]> // true
151 type __ = IsEmptyTuple<[1]> // false
152 type ___ = IsEmptyTuple<number[]> // false
153
154}
155/**
156 * If Cache is empty return Prop without dot,
157 * to avoid ".user"
158 */
159type HandleDot<
160 Cache extends string,
161 Prop extends string | number
162 > =
163 Cache extends ''
164 ? `${Prop}`
165 : `${Cache}.${Prop}`
166
167/**
168 * Simple iteration through object properties
169 */
170type HandleObject<Obj, Cache extends string> = {
171 [Prop in keyof Obj]:
172 // concat previous Cacha and Prop
173 | HandleDot<Cache, Prop & string>
174 // with next Cache and Prop
175 | Path<Obj[Prop], HandleDot<Cache, Prop & string>>
176}[keyof Obj]
177
178type Path<Obj, Cache extends string = ''> =
179 // if Obj is primitive
180 (Obj extends PropertyKey
181 // return Cache
182 ? Cache
183 // if Obj is Array (can be array, tuple, empty tuple)
184 : (Obj extends Array<unknown>
185 // and is tuple
186 ? (IsTuple<Obj> extends true
187 // and tuple is empty
188 ? (IsEmptyTuple<Obj> extends true
189 // call recursively Path with `-1` as an allowed index
190 ? Path<PropertyKey, HandleDot<Cache, -1>>
191 // if tuple is not empty we can handle it as regular object
192 : HandleObject<Obj, Cache>)
193 // if Obj is regular array call Path with union of all elements
194 : Path<Obj[number], HandleDot<Cache, number>>)
195 // if Obj is neither Array nor Tuple nor Primitive - treat is as object
196 : HandleObject<Obj, Cache>)
197 )
198
199// "user" | "user.arr" | `user.arr.${number}`
200type Test = Extract<Path<Structure>, string>
201type WithDot<T extends string> = T extends `${string}.${string}` ? T : never
202type KeysUnion<T, Cache extends string = '', Level extends any[] = []> =
203 T extends PropertyKey ? Cache : {
204 [P in keyof T]:
205 P extends string
206 ? Cache extends ''
207 ? KeysUnion<T[P], `${P}`, [...Level, 1]>
208 : Level['length'] extends 1 // if it is a higher level - proceed
209 ? KeysUnion<T[P], `${Cache}.${P}`, [...Level, 1]>
210 : Level['length'] extends 2 // stop on second level
211 ? Cache | KeysUnion<T[P], `${Cache}`, [...Level, 1]>
212 : never
213 : never
214 }[keyof T]
215
216type Acc = Record<string, any>
217
218type ReducerCallback<Accumulator extends Acc, El extends string> =
219 El extends keyof Accumulator ? Accumulator[El] : Accumulator
220
221type Reducer<
222 Keys extends string,
223 Accumulator extends Acc = {}
224 > =
225 // Key destructure
226 Keys extends `${infer Prop}.${infer Rest}`
227 // call Reducer with callback, just like in JS
228 ? Reducer<Rest, ReducerCallback<Accumulator, Prop>>
229 // this is the last part of path because no dot
230 : Keys extends `${infer Last}`
231 // call reducer with last part
232 ? ReducerCallback<Accumulator, Last>
233 : never
234
235{
236 type _ = Reducer<'user.arr', Structure> // []
237 type __ = Reducer<'user', Structure> // { arr: [] }
238}
239
You can find more information about using Reduce
in my blog.
Whole code:
1interface IPerson {
2 name: string;
3 age: number;
4 contact: {
5 address: string;
6 visitDate: Date;
7 }
8}
9type TPerson = {
10 name: string;
11 age: number;
12 contact: { address: string; visitDate: Date; }
13 "contact.address": string;
14 "contact.visitDate": Date;
15}
16interface IPerson {
17 contact: {
18 address: string;
19 visitDate: Date;
20 }[]
21}
22type TPerson = {
23 [x: `contact.${number}.address`]: string;
24 [x: `contact.${number}.visitDate`]: Date;
25 contact: {
26 address: string;
27 visitDate: Date;
28 }[];
29}
30interface IPerson {
31 contact: [string, Date]
32}
33type TPerson = {
34 [x: `contact.0`]: string;
35 [x: `contact.1`]: Date;
36 contact: [string, Date];
37}
38interface IPerson {
39 readonly _id: string;
40 age: number;
41 readonly _created_date: Date;
42}
43type TPerson = {
44 age: number;
45}
46interface IPerson {
47 contact: {
48 address: string;
49 visitDate?: Date;
50 }[];
51}
52type TPerson = {
53 [x: `contact.${number}.address`]: string;
54 [x: `contact.${number}.visitDate`]?: Date;
55 contact: {
56 address: string;
57 visitDate?: Date;
58 }[];
59}
60interface IPerson {
61 contact: { address: string; } & { visitDate: Date; }
62}
63type TPerson = {
64 [x: `contact.address`]: string;
65 [x: `contact.visitDate`]?: Date;
66 contact: { address: string; } & { visitDate: Date; }
67}
68interface IPerson {
69 birth: Date;
70}
71type TPerson = {
72 birth: Date;
73}
74type TPerson = {
75 age: Date;
76 "age.toDateString": () => string;
77 "age.toTimeString": () => string;
78 "age.toLocaleDateString": {
79 ...
80}
81type Structure = {
82 user: {
83 name: string,
84 surname: string
85 }
86}
87
88type BlackMagic<T>= T
89
90// user.name | user.surname
91type Result=BlackMagic<Structure>
92type Structure = {
93 user: {
94 arr: [1, 2],
95 }
96}
97
98type BlackMagic<T> = T
99
100// "user.arr" | "user.arr.0" | "user.arr.1"
101type Result = BlackMagic<Structure>
102type Structure = {
103 user: {
104 arr: number[],
105 }
106}
107
108type BlackMagic<T> = T
109
110// "user.arr" | `user.arr.${number}`
111type Result = BlackMagic<Structure>
112type Structure = {
113 user: {
114 arr: [],
115 }
116}
117
118type BlackMagic<T> = T
119
120// "user.arr" | "user.arr.-1"
121type Result = BlackMagic<Structure>
122type Values<T> = T[keyof T]
123{
124 // 1 | "John"
125 type _ = Values<{ age: 1, name: 'John' }>
126}
127
128type IsNever<T> = [T] extends [never] ? true : false;
129{
130 type _ = IsNever<never> // true
131 type __ = IsNever<true> // false
132}
133
134type IsTuple<T> =
135 (T extends Array<any> ?
136 (T['length'] extends number
137 ? (number extends T['length']
138 ? false
139 : true)
140 : true)
141 : false)
142{
143 type _ = IsTuple<[1, 2]> // true
144 type __ = IsTuple<number[]> // false
145 type ___ = IsTuple<{ length: 2 }> // false
146}
147
148type IsEmptyTuple<T extends Array<any>> = T['length'] extends 0 ? true : false
149{
150 type _ = IsEmptyTuple<[]> // true
151 type __ = IsEmptyTuple<[1]> // false
152 type ___ = IsEmptyTuple<number[]> // false
153
154}
155/**
156 * If Cache is empty return Prop without dot,
157 * to avoid ".user"
158 */
159type HandleDot<
160 Cache extends string,
161 Prop extends string | number
162 > =
163 Cache extends ''
164 ? `${Prop}`
165 : `${Cache}.${Prop}`
166
167/**
168 * Simple iteration through object properties
169 */
170type HandleObject<Obj, Cache extends string> = {
171 [Prop in keyof Obj]:
172 // concat previous Cacha and Prop
173 | HandleDot<Cache, Prop & string>
174 // with next Cache and Prop
175 | Path<Obj[Prop], HandleDot<Cache, Prop & string>>
176}[keyof Obj]
177
178type Path<Obj, Cache extends string = ''> =
179 // if Obj is primitive
180 (Obj extends PropertyKey
181 // return Cache
182 ? Cache
183 // if Obj is Array (can be array, tuple, empty tuple)
184 : (Obj extends Array<unknown>
185 // and is tuple
186 ? (IsTuple<Obj> extends true
187 // and tuple is empty
188 ? (IsEmptyTuple<Obj> extends true
189 // call recursively Path with `-1` as an allowed index
190 ? Path<PropertyKey, HandleDot<Cache, -1>>
191 // if tuple is not empty we can handle it as regular object
192 : HandleObject<Obj, Cache>)
193 // if Obj is regular array call Path with union of all elements
194 : Path<Obj[number], HandleDot<Cache, number>>)
195 // if Obj is neither Array nor Tuple nor Primitive - treat is as object
196 : HandleObject<Obj, Cache>)
197 )
198
199// "user" | "user.arr" | `user.arr.${number}`
200type Test = Extract<Path<Structure>, string>
201type WithDot<T extends string> = T extends `${string}.${string}` ? T : never
202type KeysUnion<T, Cache extends string = '', Level extends any[] = []> =
203 T extends PropertyKey ? Cache : {
204 [P in keyof T]:
205 P extends string
206 ? Cache extends ''
207 ? KeysUnion<T[P], `${P}`, [...Level, 1]>
208 : Level['length'] extends 1 // if it is a higher level - proceed
209 ? KeysUnion<T[P], `${Cache}.${P}`, [...Level, 1]>
210 : Level['length'] extends 2 // stop on second level
211 ? Cache | KeysUnion<T[P], `${Cache}`, [...Level, 1]>
212 : never
213 : never
214 }[keyof T]
215
216type Acc = Record<string, any>
217
218type ReducerCallback<Accumulator extends Acc, El extends string> =
219 El extends keyof Accumulator ? Accumulator[El] : Accumulator
220
221type Reducer<
222 Keys extends string,
223 Accumulator extends Acc = {}
224 > =
225 // Key destructure
226 Keys extends `${infer Prop}.${infer Rest}`
227 // call Reducer with callback, just like in JS
228 ? Reducer<Rest, ReducerCallback<Accumulator, Prop>>
229 // this is the last part of path because no dot
230 : Keys extends `${infer Last}`
231 // call reducer with last part
232 ? ReducerCallback<Accumulator, Last>
233 : never
234
235{
236 type _ = Reducer<'user.arr', Structure> // []
237 type __ = Reducer<'user', Structure> // { arr: [] }
238}
239type Structure = {
240 user: {
241 tuple: [42],
242 emptyTuple: [],
243 array: { age: number }[]
244 }
245}
246
247
248type Values<T> = T[keyof T]
249{
250 // 1 | "John"
251 type _ = Values<{ age: 1, name: 'John' }>
252}
253
254type IsNever<T> = [T] extends [never] ? true : false;
255{
256 type _ = IsNever<never> // true
257 type __ = IsNever<true> // false
258}
259
260type IsTuple<T> =
261 (T extends Array<any> ?
262 (T['length'] extends number
263 ? (number extends T['length']
264 ? false
265 : true)
266 : true)
267 : false)
268{
269 type _ = IsTuple<[1, 2]> // true
270 type __ = IsTuple<number[]> // false
271 type ___ = IsTuple<{ length: 2 }> // false
272}
273
274type IsEmptyTuple<T extends Array<any>> = T['length'] extends 0 ? true : false
275{
276 type _ = IsEmptyTuple<[]> // true
277 type __ = IsEmptyTuple<[1]> // false
278 type ___ = IsEmptyTuple<number[]> // false
279}
280
281/**
282 * If Cache is empty return Prop without dot,
283 * to avoid ".user"
284 */
285type HandleDot<
286 Cache extends string,
287 Prop extends string | number
288 > =
289 Cache extends ''
290 ? `${Prop}`
291 : `${Cache}.${Prop}`
292
293/**
294 * Simple iteration through object properties
295 */
296type HandleObject<Obj, Cache extends string> = {
297 [Prop in keyof Obj]:
298 // concat previous Cacha and Prop
299 | HandleDot<Cache, Prop & string>
300 // with next Cache and Prop
301 | Path<Obj[Prop], HandleDot<Cache, Prop & string>>
302}[keyof Obj]
303
304type Path<Obj, Cache extends string = ''> =
305 (Obj extends PropertyKey
306 // return Cache
307 ? Cache
308 // if Obj is Array (can be array, tuple, empty tuple)
309 : (Obj extends Array<unknown>
310 // and is tuple
311 ? (IsTuple<Obj> extends true
312 // and tuple is empty
313 ? (IsEmptyTuple<Obj> extends true
314 // call recursively Path with `-1` as an allowed index
315 ? Path<PropertyKey, HandleDot<Cache, -1>>
316 // if tuple is not empty we can handle it as regular object
317 : HandleObject<Obj, Cache>)
318 // if Obj is regular array call Path with union of all elements
319 : Path<Obj[number], HandleDot<Cache, number>>)
320 // if Obj is neither Array nor Tuple nor Primitive - treat is as object
321 : HandleObject<Obj, Cache>)
322 )
323
324type WithDot<T extends string> = T extends `${string}.${string}` ? T : never
325
326
327// "user" | "user.arr" | `user.arr.${number}`
328type Test = WithDot<Extract<Path<Structure>, string>>
329
330
331
332type Acc = Record<string, any>
333
334type ReducerCallback<Accumulator extends Acc, El extends string> =
335 El extends keyof Accumulator ? Accumulator[El] : El extends '-1' ? never : Accumulator
336
337type Reducer<
338 Keys extends string,
339 Accumulator extends Acc = {}
340 > =
341 // Key destructure
342 Keys extends `${infer Prop}.${infer Rest}`
343 // call Reducer with callback, just like in JS
344 ? Reducer<Rest, ReducerCallback<Accumulator, Prop>>
345 // this is the last part of path because no dot
346 : Keys extends `${infer Last}`
347 // call reducer with last part
348 ? ReducerCallback<Accumulator, Last>
349 : never
350
351{
352 type _ = Reducer<'user.arr', Structure> // []
353 type __ = Reducer<'user', Structure> // { arr: [] }
354}
355
356type BlackMagic<T> = T & {
357 [Prop in WithDot<Extract<Path<T>, string>>]: Reducer<Prop, T>
358}
359
360type Result = BlackMagic<Structure>
361
This implementation is worth considering
Community Discussions contain sources that include Stack Exchange Network
Tutorials and Learning Resources in Autocomplete
Tutorials and Learning Resources are not available at this moment for Autocomplete