componentProps.ts 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. import {
  2. toRaw,
  3. shallowReactive,
  4. trigger,
  5. TriggerOpTypes
  6. } from '@vue/reactivity'
  7. import {
  8. EMPTY_OBJ,
  9. camelize,
  10. hyphenate,
  11. capitalize,
  12. isString,
  13. isFunction,
  14. isArray,
  15. isObject,
  16. hasOwn,
  17. toRawType,
  18. PatchFlags,
  19. makeMap,
  20. isReservedProp,
  21. EMPTY_ARR,
  22. def,
  23. extend,
  24. isOn
  25. } from '@vue/shared'
  26. import { warn } from './warning'
  27. import {
  28. Data,
  29. ComponentInternalInstance,
  30. ComponentOptions,
  31. ConcreteComponent,
  32. setCurrentInstance,
  33. unsetCurrentInstance
  34. } from './component'
  35. import { isEmitListener } from './componentEmits'
  36. import { InternalObjectKey } from './vnode'
  37. import { AppContext } from './apiCreateApp'
  38. import { createPropsDefaultThis } from './compat/props'
  39. import { isCompatEnabled, softAssertCompatEnabled } from './compat/compatConfig'
  40. import { DeprecationTypes } from './compat/compatConfig'
  41. import { shouldSkipAttr } from './compat/attrsFallthrough'
  42. export type ComponentPropsOptions<P = Data> =
  43. | ComponentObjectPropsOptions<P>
  44. | string[]
  45. export type ComponentObjectPropsOptions<P = Data> = {
  46. [K in keyof P]: Prop<P[K]> | null
  47. }
  48. export type Prop<T, D = T> = PropOptions<T, D> | PropType<T>
  49. type DefaultFactory<T> = (props: Data) => T | null | undefined
  50. export interface PropOptions<T = any, D = T> {
  51. type?: PropType<T> | true | null
  52. required?: boolean
  53. default?: D | DefaultFactory<D> | null | undefined | object
  54. validator?(value: unknown): boolean
  55. }
  56. export type PropType<T> = PropConstructor<T> | PropConstructor<T>[]
  57. type PropConstructor<T = any> =
  58. | { new (...args: any[]): T & {} }
  59. | { (): T }
  60. | PropMethod<T>
  61. type PropMethod<T, TConstructor = any> = [T] extends [
  62. ((...args: any) => any) | undefined
  63. ] // if is function with args, allowing non-required functions
  64. ? { new (): TConstructor; (): T; readonly prototype: TConstructor } // Create Function like constructor
  65. : never
  66. type RequiredKeys<T> = {
  67. [K in keyof T]: T[K] extends
  68. | { required: true }
  69. | { default: any }
  70. // don't mark Boolean props as undefined
  71. | BooleanConstructor
  72. | { type: BooleanConstructor }
  73. ? T[K] extends { default: undefined | (() => undefined) }
  74. ? never
  75. : K
  76. : never
  77. }[keyof T]
  78. type OptionalKeys<T> = Exclude<keyof T, RequiredKeys<T>>
  79. type DefaultKeys<T> = {
  80. [K in keyof T]: T[K] extends
  81. | { default: any }
  82. // Boolean implicitly defaults to false
  83. | BooleanConstructor
  84. | { type: BooleanConstructor }
  85. ? T[K] extends { type: BooleanConstructor; required: true } // not default if Boolean is marked as required
  86. ? never
  87. : K
  88. : never
  89. }[keyof T]
  90. type InferPropType<T> = [T] extends [null]
  91. ? any // null & true would fail to infer
  92. : [T] extends [{ type: null | true }]
  93. ? any // As TS issue https://github.com/Microsoft/TypeScript/issues/14829 // somehow `ObjectConstructor` when inferred from { (): T } becomes `any` // `BooleanConstructor` when inferred from PropConstructor(with PropMethod) becomes `Boolean`
  94. : [T] extends [ObjectConstructor | { type: ObjectConstructor }]
  95. ? Record<string, any>
  96. : [T] extends [BooleanConstructor | { type: BooleanConstructor }]
  97. ? boolean
  98. : [T] extends [DateConstructor | { type: DateConstructor }]
  99. ? Date
  100. : [T] extends [(infer U)[] | { type: (infer U)[] }]
  101. ? U extends DateConstructor
  102. ? Date | InferPropType<U>
  103. : InferPropType<U>
  104. : [T] extends [Prop<infer V, infer D>]
  105. ? unknown extends V
  106. ? D
  107. : V
  108. : T
  109. export type ExtractPropTypes<O> = O extends object
  110. ? { [K in keyof O]?: unknown } & // This is needed to keep the relation between the option prop and the props, allowing to use ctrl+click to navigate to the prop options. see: #3656
  111. { [K in RequiredKeys<O>]: InferPropType<O[K]> } &
  112. { [K in OptionalKeys<O>]?: InferPropType<O[K]> }
  113. : { [K in string]: any }
  114. const enum BooleanFlags {
  115. shouldCast,
  116. shouldCastTrue
  117. }
  118. // extract props which defined with default from prop options
  119. export type ExtractDefaultPropTypes<O> = O extends object
  120. ? { [K in DefaultKeys<O>]: InferPropType<O[K]> }
  121. : {}
  122. type NormalizedProp =
  123. | null
  124. | (PropOptions & {
  125. [BooleanFlags.shouldCast]?: boolean
  126. [BooleanFlags.shouldCastTrue]?: boolean
  127. })
  128. // normalized value is a tuple of the actual normalized options
  129. // and an array of prop keys that need value casting (booleans and defaults)
  130. export type NormalizedProps = Record<string, NormalizedProp>
  131. export type NormalizedPropsOptions = [NormalizedProps, string[]] | []
  132. export function initProps(
  133. instance: ComponentInternalInstance,
  134. rawProps: Data | null,
  135. isStateful: number, // result of bitwise flag comparison
  136. isSSR = false
  137. ) {
  138. const props: Data = {}
  139. const attrs: Data = {}
  140. def(attrs, InternalObjectKey, 1)
  141. instance.propsDefaults = Object.create(null)
  142. setFullProps(instance, rawProps, props, attrs)
  143. // ensure all declared prop keys are present
  144. for (const key in instance.propsOptions[0]) {
  145. if (!(key in props)) {
  146. props[key] = undefined
  147. }
  148. }
  149. // validation
  150. if (__DEV__) {
  151. validateProps(rawProps || {}, props, instance)
  152. }
  153. if (isStateful) {
  154. // stateful
  155. instance.props = isSSR ? props : shallowReactive(props)
  156. } else {
  157. if (!instance.type.props) {
  158. // functional w/ optional props, props === attrs
  159. instance.props = attrs
  160. } else {
  161. // functional w/ declared props
  162. instance.props = props
  163. }
  164. }
  165. instance.attrs = attrs
  166. }
  167. export function updateProps(
  168. instance: ComponentInternalInstance,
  169. rawProps: Data | null,
  170. rawPrevProps: Data | null,
  171. optimized: boolean
  172. ) {
  173. const {
  174. props,
  175. attrs,
  176. vnode: { patchFlag }
  177. } = instance
  178. const rawCurrentProps = toRaw(props)
  179. const [options] = instance.propsOptions
  180. let hasAttrsChanged = false
  181. if (
  182. // always force full diff in dev
  183. // - #1942 if hmr is enabled with sfc component
  184. // - vite#872 non-sfc component used by sfc component
  185. !(
  186. __DEV__ &&
  187. (instance.type.__hmrId ||
  188. (instance.parent && instance.parent.type.__hmrId))
  189. ) &&
  190. (optimized || patchFlag > 0) &&
  191. !(patchFlag & PatchFlags.FULL_PROPS)
  192. ) {
  193. if (patchFlag & PatchFlags.PROPS) {
  194. // Compiler-generated props & no keys change, just set the updated
  195. // the props.
  196. const propsToUpdate = instance.vnode.dynamicProps!
  197. for (let i = 0; i < propsToUpdate.length; i++) {
  198. let key = propsToUpdate[i]
  199. // PROPS flag guarantees rawProps to be non-null
  200. const value = rawProps![key]
  201. if (options) {
  202. // attr / props separation was done on init and will be consistent
  203. // in this code path, so just check if attrs have it.
  204. if (hasOwn(attrs, key)) {
  205. if (value !== attrs[key]) {
  206. attrs[key] = value
  207. hasAttrsChanged = true
  208. }
  209. } else {
  210. const camelizedKey = camelize(key)
  211. props[camelizedKey] = resolvePropValue(
  212. options,
  213. rawCurrentProps,
  214. camelizedKey,
  215. value,
  216. instance,
  217. false /* isAbsent */
  218. )
  219. }
  220. } else {
  221. if (__COMPAT__) {
  222. if (isOn(key) && key.endsWith('Native')) {
  223. key = key.slice(0, -6) // remove Native postfix
  224. } else if (shouldSkipAttr(key, instance)) {
  225. continue
  226. }
  227. }
  228. if (value !== attrs[key]) {
  229. attrs[key] = value
  230. hasAttrsChanged = true
  231. }
  232. }
  233. }
  234. }
  235. } else {
  236. // full props update.
  237. if (setFullProps(instance, rawProps, props, attrs)) {
  238. hasAttrsChanged = true
  239. }
  240. // in case of dynamic props, check if we need to delete keys from
  241. // the props object
  242. let kebabKey: string
  243. for (const key in rawCurrentProps) {
  244. if (
  245. !rawProps ||
  246. // for camelCase
  247. (!hasOwn(rawProps, key) &&
  248. // it's possible the original props was passed in as kebab-case
  249. // and converted to camelCase (#955)
  250. ((kebabKey = hyphenate(key)) === key || !hasOwn(rawProps, kebabKey)))
  251. ) {
  252. if (options) {
  253. if (
  254. rawPrevProps &&
  255. // for camelCase
  256. (rawPrevProps[key] !== undefined ||
  257. // for kebab-case
  258. rawPrevProps[kebabKey!] !== undefined)
  259. ) {
  260. props[key] = resolvePropValue(
  261. options,
  262. rawCurrentProps,
  263. key,
  264. undefined,
  265. instance,
  266. true /* isAbsent */
  267. )
  268. }
  269. } else {
  270. delete props[key]
  271. }
  272. }
  273. }
  274. // in the case of functional component w/o props declaration, props and
  275. // attrs point to the same object so it should already have been updated.
  276. if (attrs !== rawCurrentProps) {
  277. for (const key in attrs) {
  278. if (!rawProps || !hasOwn(rawProps, key)) {
  279. delete attrs[key]
  280. hasAttrsChanged = true
  281. }
  282. }
  283. }
  284. }
  285. // trigger updates for $attrs in case it's used in component slots
  286. if (hasAttrsChanged) {
  287. trigger(instance, TriggerOpTypes.SET, '$attrs')
  288. }
  289. if (__DEV__) {
  290. validateProps(rawProps || {}, props, instance)
  291. }
  292. }
  293. function setFullProps(
  294. instance: ComponentInternalInstance,
  295. rawProps: Data | null,
  296. props: Data,
  297. attrs: Data
  298. ) {
  299. const [options, needCastKeys] = instance.propsOptions
  300. let hasAttrsChanged = false
  301. let rawCastValues: Data | undefined
  302. if (rawProps) {
  303. for (let key in rawProps) {
  304. // key, ref are reserved and never passed down
  305. if (isReservedProp(key)) {
  306. continue
  307. }
  308. if (__COMPAT__) {
  309. if (key.startsWith('onHook:')) {
  310. softAssertCompatEnabled(
  311. DeprecationTypes.INSTANCE_EVENT_HOOKS,
  312. instance,
  313. key.slice(2).toLowerCase()
  314. )
  315. }
  316. if (key === 'inline-template') {
  317. continue
  318. }
  319. }
  320. const value = rawProps[key]
  321. // prop option names are camelized during normalization, so to support
  322. // kebab -> camel conversion here we need to camelize the key.
  323. let camelKey
  324. if (options && hasOwn(options, (camelKey = camelize(key)))) {
  325. if (!needCastKeys || !needCastKeys.includes(camelKey)) {
  326. props[camelKey] = value
  327. } else {
  328. ;(rawCastValues || (rawCastValues = {}))[camelKey] = value
  329. }
  330. } else if (!isEmitListener(instance.emitsOptions, key)) {
  331. // Any non-declared (either as a prop or an emitted event) props are put
  332. // into a separate `attrs` object for spreading. Make sure to preserve
  333. // original key casing
  334. if (__COMPAT__) {
  335. if (isOn(key) && key.endsWith('Native')) {
  336. key = key.slice(0, -6) // remove Native postfix
  337. } else if (shouldSkipAttr(key, instance)) {
  338. continue
  339. }
  340. }
  341. if (value !== attrs[key]) {
  342. attrs[key] = value
  343. hasAttrsChanged = true
  344. }
  345. }
  346. }
  347. }
  348. if (needCastKeys) {
  349. const rawCurrentProps = toRaw(props)
  350. const castValues = rawCastValues || EMPTY_OBJ
  351. for (let i = 0; i < needCastKeys.length; i++) {
  352. const key = needCastKeys[i]
  353. props[key] = resolvePropValue(
  354. options!,
  355. rawCurrentProps,
  356. key,
  357. castValues[key],
  358. instance,
  359. !hasOwn(castValues, key)
  360. )
  361. }
  362. }
  363. return hasAttrsChanged
  364. }
  365. function resolvePropValue(
  366. options: NormalizedProps,
  367. props: Data,
  368. key: string,
  369. value: unknown,
  370. instance: ComponentInternalInstance,
  371. isAbsent: boolean
  372. ) {
  373. const opt = options[key]
  374. if (opt != null) {
  375. const hasDefault = hasOwn(opt, 'default')
  376. // default values
  377. if (hasDefault && value === undefined) {
  378. const defaultValue = opt.default
  379. if (opt.type !== Function && isFunction(defaultValue)) {
  380. const { propsDefaults } = instance
  381. if (key in propsDefaults) {
  382. value = propsDefaults[key]
  383. } else {
  384. setCurrentInstance(instance)
  385. value = propsDefaults[key] = defaultValue.call(
  386. __COMPAT__ &&
  387. isCompatEnabled(DeprecationTypes.PROPS_DEFAULT_THIS, instance)
  388. ? createPropsDefaultThis(instance, props, key)
  389. : null,
  390. props
  391. )
  392. unsetCurrentInstance()
  393. }
  394. } else {
  395. value = defaultValue
  396. }
  397. }
  398. // boolean casting
  399. if (opt[BooleanFlags.shouldCast]) {
  400. if (isAbsent && !hasDefault) {
  401. value = false
  402. } else if (
  403. opt[BooleanFlags.shouldCastTrue] &&
  404. (value === '' || value === hyphenate(key))
  405. ) {
  406. value = true
  407. }
  408. }
  409. }
  410. return value
  411. }
  412. export function normalizePropsOptions(
  413. comp: ConcreteComponent,
  414. appContext: AppContext,
  415. asMixin = false
  416. ): NormalizedPropsOptions {
  417. const cache = appContext.propsCache
  418. const cached = cache.get(comp)
  419. if (cached) {
  420. return cached
  421. }
  422. const raw = comp.props
  423. const normalized: NormalizedPropsOptions[0] = {}
  424. const needCastKeys: NormalizedPropsOptions[1] = []
  425. // apply mixin/extends props
  426. let hasExtends = false
  427. if (__FEATURE_OPTIONS_API__ && !isFunction(comp)) {
  428. const extendProps = (raw: ComponentOptions) => {
  429. if (__COMPAT__ && isFunction(raw)) {
  430. raw = raw.options
  431. }
  432. hasExtends = true
  433. const [props, keys] = normalizePropsOptions(raw, appContext, true)
  434. extend(normalized, props)
  435. if (keys) needCastKeys.push(...keys)
  436. }
  437. if (!asMixin && appContext.mixins.length) {
  438. appContext.mixins.forEach(extendProps)
  439. }
  440. if (comp.extends) {
  441. extendProps(comp.extends)
  442. }
  443. if (comp.mixins) {
  444. comp.mixins.forEach(extendProps)
  445. }
  446. }
  447. if (!raw && !hasExtends) {
  448. cache.set(comp, EMPTY_ARR as any)
  449. return EMPTY_ARR as any
  450. }
  451. if (isArray(raw)) {
  452. for (let i = 0; i < raw.length; i++) {
  453. if (__DEV__ && !isString(raw[i])) {
  454. warn(`props must be strings when using array syntax.`, raw[i])
  455. }
  456. const normalizedKey = camelize(raw[i])
  457. if (validatePropName(normalizedKey)) {
  458. normalized[normalizedKey] = EMPTY_OBJ
  459. }
  460. }
  461. } else if (raw) {
  462. if (__DEV__ && !isObject(raw)) {
  463. warn(`invalid props options`, raw)
  464. }
  465. for (const key in raw) {
  466. const normalizedKey = camelize(key)
  467. if (validatePropName(normalizedKey)) {
  468. const opt = raw[key]
  469. const prop: NormalizedProp = (normalized[normalizedKey] =
  470. isArray(opt) || isFunction(opt) ? { type: opt } : opt)
  471. if (prop) {
  472. const booleanIndex = getTypeIndex(Boolean, prop.type)
  473. const stringIndex = getTypeIndex(String, prop.type)
  474. prop[BooleanFlags.shouldCast] = booleanIndex > -1
  475. prop[BooleanFlags.shouldCastTrue] =
  476. stringIndex < 0 || booleanIndex < stringIndex
  477. // if the prop needs boolean casting or default value
  478. if (booleanIndex > -1 || hasOwn(prop, 'default')) {
  479. needCastKeys.push(normalizedKey)
  480. }
  481. }
  482. }
  483. }
  484. }
  485. const res: NormalizedPropsOptions = [normalized, needCastKeys]
  486. cache.set(comp, res)
  487. return res
  488. }
  489. function validatePropName(key: string) {
  490. if (key[0] !== '$') {
  491. return true
  492. } else if (__DEV__) {
  493. warn(`Invalid prop name: "${key}" is a reserved property.`)
  494. }
  495. return false
  496. }
  497. // use function string name to check type constructors
  498. // so that it works across vms / iframes.
  499. function getType(ctor: Prop<any>): string {
  500. const match = ctor && ctor.toString().match(/^\s*function (\w+)/)
  501. return match ? match[1] : ctor === null ? 'null' : ''
  502. }
  503. function isSameType(a: Prop<any>, b: Prop<any>): boolean {
  504. return getType(a) === getType(b)
  505. }
  506. function getTypeIndex(
  507. type: Prop<any>,
  508. expectedTypes: PropType<any> | void | null | true
  509. ): number {
  510. if (isArray(expectedTypes)) {
  511. return expectedTypes.findIndex(t => isSameType(t, type))
  512. } else if (isFunction(expectedTypes)) {
  513. return isSameType(expectedTypes, type) ? 0 : -1
  514. }
  515. return -1
  516. }
  517. /**
  518. * dev only
  519. */
  520. function validateProps(
  521. rawProps: Data,
  522. props: Data,
  523. instance: ComponentInternalInstance
  524. ) {
  525. const resolvedValues = toRaw(props)
  526. const options = instance.propsOptions[0]
  527. for (const key in options) {
  528. let opt = options[key]
  529. if (opt == null) continue
  530. validateProp(
  531. key,
  532. resolvedValues[key],
  533. opt,
  534. !hasOwn(rawProps, key) && !hasOwn(rawProps, hyphenate(key))
  535. )
  536. }
  537. }
  538. /**
  539. * dev only
  540. */
  541. function validateProp(
  542. name: string,
  543. value: unknown,
  544. prop: PropOptions,
  545. isAbsent: boolean
  546. ) {
  547. const { type, required, validator } = prop
  548. // required!
  549. if (required && isAbsent) {
  550. warn('Missing required prop: "' + name + '"')
  551. return
  552. }
  553. // missing but optional
  554. if (value == null && !prop.required) {
  555. return
  556. }
  557. // type check
  558. if (type != null && type !== true) {
  559. let isValid = false
  560. const types = isArray(type) ? type : [type]
  561. const expectedTypes = []
  562. // value is valid as long as one of the specified types match
  563. for (let i = 0; i < types.length && !isValid; i++) {
  564. const { valid, expectedType } = assertType(value, types[i])
  565. expectedTypes.push(expectedType || '')
  566. isValid = valid
  567. }
  568. if (!isValid) {
  569. warn(getInvalidTypeMessage(name, value, expectedTypes))
  570. return
  571. }
  572. }
  573. // custom validator
  574. if (validator && !validator(value)) {
  575. warn('Invalid prop: custom validator check failed for prop "' + name + '".')
  576. }
  577. }
  578. const isSimpleType = /*#__PURE__*/ makeMap(
  579. 'String,Number,Boolean,Function,Symbol,BigInt'
  580. )
  581. type AssertionResult = {
  582. valid: boolean
  583. expectedType: string
  584. }
  585. /**
  586. * dev only
  587. */
  588. function assertType(value: unknown, type: PropConstructor): AssertionResult {
  589. let valid
  590. const expectedType = getType(type)
  591. if (isSimpleType(expectedType)) {
  592. const t = typeof value
  593. valid = t === expectedType.toLowerCase()
  594. // for primitive wrapper objects
  595. if (!valid && t === 'object') {
  596. valid = value instanceof type
  597. }
  598. } else if (expectedType === 'Object') {
  599. valid = isObject(value)
  600. } else if (expectedType === 'Array') {
  601. valid = isArray(value)
  602. } else if (expectedType === 'null') {
  603. valid = value === null
  604. } else {
  605. valid = value instanceof type
  606. }
  607. return {
  608. valid,
  609. expectedType
  610. }
  611. }
  612. /**
  613. * dev only
  614. */
  615. function getInvalidTypeMessage(
  616. name: string,
  617. value: unknown,
  618. expectedTypes: string[]
  619. ): string {
  620. let message =
  621. `Invalid prop: type check failed for prop "${name}".` +
  622. ` Expected ${expectedTypes.map(capitalize).join(' | ')}`
  623. const expectedType = expectedTypes[0]
  624. const receivedType = toRawType(value)
  625. const expectedValue = styleValue(value, expectedType)
  626. const receivedValue = styleValue(value, receivedType)
  627. // check if we need to specify expected value
  628. if (
  629. expectedTypes.length === 1 &&
  630. isExplicable(expectedType) &&
  631. !isBoolean(expectedType, receivedType)
  632. ) {
  633. message += ` with value ${expectedValue}`
  634. }
  635. message += `, got ${receivedType} `
  636. // check if we need to specify received value
  637. if (isExplicable(receivedType)) {
  638. message += `with value ${receivedValue}.`
  639. }
  640. return message
  641. }
  642. /**
  643. * dev only
  644. */
  645. function styleValue(value: unknown, type: string): string {
  646. if (type === 'String') {
  647. return `"${value}"`
  648. } else if (type === 'Number') {
  649. return `${Number(value)}`
  650. } else {
  651. return `${value}`
  652. }
  653. }
  654. /**
  655. * dev only
  656. */
  657. function isExplicable(type: string): boolean {
  658. const explicitTypes = ['string', 'number', 'boolean']
  659. return explicitTypes.some(elem => type.toLowerCase() === elem)
  660. }
  661. /**
  662. * dev only
  663. */
  664. function isBoolean(...args: string[]): boolean {
  665. return args.some(elem => elem.toLowerCase() === 'boolean')
  666. }