66
77// Former goog.module ID: Blockly.fieldRegistry
88
9- import type { Field , FieldProto } from './field.js' ;
9+ import type { Field , FieldConfig } from './field.js' ;
1010import * as registry from './registry.js' ;
1111
12- interface RegistryOptions {
12+ /**
13+ * When constructing a field from JSON using the registry, the
14+ * `fromJson` method in this file is called with an options parameter
15+ * object consisting of the "type" which is the name of the field, and
16+ * other options that are part of the field's config object.
17+ *
18+ * These options are then passed to the field's static `fromJson`
19+ * method. That method accepts an options parameter with a type that usually
20+ * extends from FieldConfig, and may or may not have a "type" attribute (in
21+ * fact, it shouldn't, because we'd overwrite it as described above!)
22+ *
23+ * Unfortunately the registry has no way of knowing the actual Field subclass
24+ * that will be returned from passing in the name of the field. Therefore it
25+ * also has no way of knowing that the options object not only implements
26+ * `FieldConfig`, but it also should satisfy the Config that belongs to that
27+ * specific class's `fromJson` method.
28+ *
29+ * Because of this uncertainty, we just give up on type checking the properties
30+ * passed to the `fromJson` method, and allow arbitrary string keys with
31+ * unknown types.
32+ */
33+ type RegistryOptions = FieldConfig & {
34+ // The name of the field, e.g. field_dropdown
1335 type : string ;
1436 [ key : string ] : unknown ;
37+ } ;
38+
39+ /**
40+ * Represents the static methods that must be defined on any
41+ * field that is registered, i.e. the constructor and fromJson methods.
42+ *
43+ * Because we don't know which Field subclass will be registered, we
44+ * are unable to typecheck the parameters of the constructor.
45+ */
46+ export interface RegistrableField {
47+ new ( ...args : any [ ] ) : Field ;
48+ fromJson ( options : FieldConfig ) : Field ;
1549}
1650
1751/**
@@ -25,7 +59,7 @@ interface RegistryOptions {
2559 * @throws {Error } if the type name is empty, the field is already registered,
2660 * or the fieldClass is not an object containing a fromJson function.
2761 */
28- export function register ( type : string , fieldClass : FieldProto ) {
62+ export function register ( type : string , fieldClass : RegistrableField ) {
2963 registry . register ( registry . Type . FIELD , type , fieldClass ) ;
3064}
3165
@@ -59,7 +93,10 @@ export function fromJson<T>(options: RegistryOptions): Field<T> | null {
5993 * @param options
6094 */
6195function fromJsonInternal < T > ( options : RegistryOptions ) : Field < T > | null {
62- const fieldObject = registry . getObject ( registry . Type . FIELD , options . type ) ;
96+ const fieldObject = registry . getObject (
97+ registry . Type . FIELD ,
98+ options . type ,
99+ ) as unknown as RegistrableField ;
63100 if ( ! fieldObject ) {
64101 console . warn (
65102 'Blockly could not create a field of type ' +
@@ -69,12 +106,8 @@ function fromJsonInternal<T>(options: RegistryOptions): Field<T> | null {
69106 ' #1584), or the registration is not being reached.' ,
70107 ) ;
71108 return null ;
72- } else if ( typeof ( fieldObject as any ) . fromJson !== 'function' ) {
73- throw new TypeError ( 'returned Field was not a IRegistrableField' ) ;
74- } else {
75- type fromJson = ( options : { } ) => Field < T > ;
76- return ( fieldObject as unknown as { fromJson : fromJson } ) . fromJson ( options ) ;
77109 }
110+ return fieldObject . fromJson ( options ) ;
78111}
79112
80113export const TEST_ONLY = {
0 commit comments